hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?
题意:给定一个由小写字母组成的长度为 n 的字符串,首尾相连,可以从任意一个字符开始,顺时针或逆时针取这个串(长度为 n),求一个字典序最大的字符串的开始字符位置和顺时针或逆时针。如果有多个字典序最大的字符串,优先选择开始位置靠前的,如果开始位置相同,优先选择顺时针。
这种字符串的问题,第一反应是后缀数组,为了达到首尾相连的目的,所以先复制了一个两倍长的该字符串,然后再将串倒置,也弄成两倍长度,得到顺逆时针的两倍长的串,并对这两个字符串分别做后缀数组,得到 sa 数组(该串字典序第几小的后缀的开始字符是第几个)由于字符串的后缀长度必然不等,因此所有后缀都有确定的名次。
由于我们需要的是该串的循环n个串,所以对于每个 2*n 的串,它的后缀中我们需要的只有前 n 个,而每个串我们需要的也只有它的前 n 个字符,那么就出现了有可能有多个后缀的前 n 个字符是相同的,但是由于后缀的存在,使这些串的名次就有了差别。因此 sa 数组中我们得到的字典序最大的一个串,它的前 n 个字符只能确定是字典序最大的其中之一,因此我们就需要在 2*n 长度的串中找到第一个符合我们要求的串。所以我从得到的字典序最大的串中取出前 n 个字符,用这个串作为模式串在 2*n 串中 KMP 。
在顺时针的串中匹配到开始位置最靠前的第一个相同的串,而因为逆时针的串是将原串的所有字符导致,所以在逆时针串中开始位置越靠前,则它在原串中的开始位置就越靠后,因此我们需要KMP匹配找出的就是在 2*n 串中开始位置最靠后并且在 n 前的一个相同串。
最后再将得到的两个串比较他们的各个情况,输出最符合要求的一个。
恩,rank竟然变成了关键字,导致我当时CE了一发。
后来在被问到的时候我仔细再想了一下,觉得顺时针貌似并不需要用KMP,因为多个前 n 个字符相同的后缀,由于开始位置靠前的后缀长度会更长,所以字典序就会更大,所以我们取一个字典序最大的后缀,它在前 n 个字符相同的后缀串中开始位置也应该是更靠前的,所以我们用后缀数组得到的字典序最大的串就应该是我们需要的一个串,暂时我还没有想到反例。
但是逆时针却必须要匹配一下,因为字典序最大的,在 2*n 的串中开始位置更靠前,但在原串中开始位置就会越靠后,所以就要匹配得到在 2*n 串中最靠后的一个。例子就是 abcabc ,逆时针取的时候字典序最大的后缀开始位置是原串中的最后一个 c ,因此我们需要找出第三个字符 c 。所以我用了KMP。
但是据说有个做法是最小表示法,然而我并不知道那是什么,所以我还是用后缀数组+KMP过的Orz……
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int MAXN=; int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
int rk[MAXN],height[MAXN];
void build_sa(int s[],int n,int m)
{
int i,j,p,*x=t1,*y=t2;
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[i]=s[i]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[i]]]=i;
for(j=;j<=n;j<<=)
{
p=;
for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小
for(i=;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[y[i]]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=;x[sa[]]=;
for(i=;i<n;i++)
x[sa[i]]=y[sa[i-]]==y[sa[i]] && y[sa[i-]+j]==y[sa[i]+j]?p-:p++;
if(p>=n)break;
m=p;//下次基数排序的最大值
}
} void getHeight(int s[],int n)
{
int i,j,k=;
for(i=;i<=n;i++)rk[sa[i]]=i;
for(i=;i<n;i++)
{
if(k)k--;
j=sa[rk[i]-];
while(s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
} char str[MAXN];
int s0[MAXN];
int s1[MAXN];
int ans0[MAXN];
int ans1[MAXN];
int pp1[MAXN],pp0[MAXN]; int check(int n){
for(int i=;i<n;++i){
if(ans0[i]<ans1[i])return ;
else if(ans0[i]>ans1[i])return ;
}
return -;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
scanf("%s",str);
for(int i=;i<=n;i++)s0[i]=str[i]-'a'+;
for(int i=;i<=n;i++)s0[n+i]=str[i]-'a'+;
s0[*n]=;
/* for(int i=0;i<=2*n;++i)printf("%d ",s0[i]);
printf("\n");*/
build_sa(s0,*n+,);
/* for(int i=0;i<=2*n;++i)printf("%d ",sa[i]);
printf("\n");*/
int p0,p1;
for(int i=*n;i>=;--i){
if(sa[i]<n){p0=sa[i];break;}
}
for(int i=;i<n;++i){
ans0[i]=s0[p0+i];
// printf("%d ",ans0[i]);
}
/* printf("\n");
printf("\n");*/ for(int i=,j=n-;i<n;i++,j--)s1[j]=str[i]-'a'+;
for(int i=,j=n-;i<n;i++,j--)s1[n+i]=str[j]-'a'+;
s1[*n]=;
/* for(int i=0;i<=2*n;++i)printf("%d ",s1[i]);
printf("\n");*/
build_sa(s1,*n+,);
/* for(int i=0;i<=2*n;++i)printf("%d ",sa[i]);
printf("\n");*/
for(int i=*n;i>=;--i){
if(sa[i]<n){p1=sa[i];break;}
}
for(int i=;i<n;++i){
ans1[i]=s1[p1+i];
// printf("%d ",ans1[i]);
} /* printf("\n");
printf("\n");
*/
int cc=check(n);
// printf("c%d\n",cc);
if(cc==-){
int i,j;
pp0[]=pp0[]=;
for(i=;i<n;++i){
j=pp0[i];
while(j&&ans0[i]!=ans0[j])j=pp0[j];
pp0[i+]=ans0[i]==ans0[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s0[i]!=ans0[j])j=pp0[j];
if(s0[i]==ans0[j])j++;
if(j==n){
p0=i-n+;
break;
}
}
pp1[]=pp1[]=;
for(i=;i<n;++i){
j=pp1[i];
while(j&&ans1[i]!=ans1[j])j=pp1[j];
pp1[i+]=ans1[i]==ans1[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s1[i]!=ans1[j])j=pp1[j];
if(s1[i]==ans1[j])j++;
if(j==n){
if(i-n+<n)p1=i-n+;
}
}
p1=n-(p1+);
// printf("p0:%d p1:%d\n",p0,p1);
if(p0<p1){
printf("%d 0\n",p0+);
}
else if(p0>p1){
printf("%d 1\n",p1+);
}
else printf("%d 0\n",p0+); }
else if(cc==){
int i,j;
pp0[]=pp0[]=;
for(i=;i<n;++i){
j=pp0[i];
while(j&&ans0[i]!=ans0[j])j=pp0[j];
pp0[i+]=ans0[i]==ans0[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s0[i]!=ans0[j])j=pp0[j];
if(s0[i]==ans0[j])j++;
if(j==n){
p0=i-n+;
break;
}
}
printf("%d 0\n",p0+);
}
else if(cc==){
int i,j;
pp1[]=pp1[]=;
for(i=;i<n;++i){
j=pp1[i];
while(j&&ans1[i]!=ans1[j])j=pp1[j];
pp1[i+]=ans1[i]==ans1[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s1[i]!=ans1[j])j=pp1[j];
if(s1[i]==ans1[j])j++;
if(j==n){
if(i-n+<n)p1=i-n+;
// p0=i-n+1;
}
}
p1=n-(p1+);
printf("%d 1\n",p1+);
}
}
return ;
}
hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?的更多相关文章
- hdu5443(2015长春赛区网络赛1007)暴力
题意:给了一个数列,有多个询问,每个询问求某个区间内的最大值 数列长度 1000,询问个数 1000,静态,并不需要RMQ这些,直接暴力 n2 查找每个询问区间取最大值就行了. #include< ...
- hdu5441(2015长春赛区网络赛1005)类最小生成树、并查集
题意:有一张无向图,一些点之间有有权边,某条路径的值等于路径上所有边的边权的最大值,而某个点对的值为这两点间所有路径的值的最小值,给出多个询问,每个询问有一个值,询问有多少点对满足其值小于等于询问值. ...
- hdu5438(2015长春赛区网络赛1002)拓扑序+DFS
题意:给出一张无向图,每个节点有各自的权值,问在点数为奇数的圈中的点的权值总和是多少. 通过拓扑序的做法标记出所有非圈上的点,做法就是加每条边的时候将两点的入度都加一,然后将所有度数为1的点入队,删去 ...
- hdu 4274 2012长春赛区网络赛 树形dp ***
设定每个节点的上限和下限,之后向上更新,判断是否出现矛盾 #include<cstdio> #include<iostream> #include<algorithm&g ...
- hdu 4277 2012长春赛区网络赛 dfs+hashmap ***
hashmap判重大法好 #include<cstdio> #include<iostream> #include<algorithm> #include<c ...
- hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***
新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...
- hdu 4272 2012长春赛区网络赛 dfs暴力 ***
总是T,以为要剪枝,后来发现加个map就行了 #include<cstdio> #include<iostream> #include<algorithm> #in ...
- Largest Point (2015沈阳赛区网络赛水题)
Problem Description Given the sequence A with n integers t1,t2,⋯,tn. Given the integral coefficients ...
- 2017青岛赛区网络赛 Smallest Minimum Cut 求最小割的最小割边数
先最大流跑一遍 在残存网络上把满流边容量+1 非满流边容量设为无穷大 在进行一次最大流即可 (这里的边都不包括建图时用于反悔的反向边) #include<cstdio> #include& ...
随机推荐
- Android listview 制作表格样式+由下往上动画弹出效果实现
效果是这样的:点击按下弹出表格的按钮,会由下往上弹出右边的列表,按下返回按钮就由上往下退出界面. 布局文件: activity_main.xml <RelativeLayout xmlns:an ...
- Spring AOP中pointcut expression表达式解析 及匹配多个条件
Spring中事务控制相关配置: <bean id="txManager" class="org.springframework.jdbc.datasource.D ...
- monkey(1)
写完应用之后,作完单元测试和功能测试,必要对应用的抗打击能力做个测试,最好的方法是雇个“猴子”在测试,猴子可以胡乱瞎按键,在这种情况下,你的应用是否还能正常工作呢?Android 测试包中提供了一个M ...
- Android 禁用以及捕捉home键
最近要做个小项目,其中有需要禁止home键的需求,一开始以为不可以,感觉得root一下才行,后来查了一下,发现还是不少朋友都实现了这个功能,现在也引用一下,供大家参考一下: 1. 在activity中 ...
- 使用windows远程桌面连接Windows Azure中的Ubuntu虚拟机
1.创建ubuntu虚拟机,这里同样不再赘述,创建过程和创建Windows虚拟机基本一样,只是登录可以选择密钥注入或者用户名密码(为了方便我选择了用户名密码认证),创建完成后,查看虚拟机详情中的端口信 ...
- (转)SoftReference
本文介绍对象的强.软.弱和虚引用的概念.应用及其在UML中的表示. 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说, ...
- ARC以及MRC中setter方法
ARC以及MRC中setter方法的差异 有时候,你会需要重写setter或者getter方法,你知道么,ARC与MRC的setter方法是有着差异的呢. 先看下MRC下的setter方法: 在看下A ...
- MATLAB里的正则表达式 [转]
正则表达式在处理字符串及文本时显得十分方便,在perl, python等脚本语言,以及java, .net等平台上都支援正则表达式.事实上,在MATLAB中也提供了正则表达式的支持.主要包含三个常用的 ...
- 20145210实验五《Java网络编程》
20145210实验五<Java网络编程> 实验内容 1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成代码, ...
- Python - 学习经验分享
执行方式: 直接输入python进入命令行,进行单行输入执行,退出后不保存. python filename.py或./filename.py 直接执行脚本文件 脚本格式: #!/usr/bin/py ...