以下题目均来自罗穗骞的论文...

No.1最长公共前缀

最长公共前缀:

题目:

给定一个字符串,询问某两个后缀的最长公共前缀。

分析:

某两个后缀的最长公共前缀就是区间height最小值,转化为RMQ问题,nlgn预处理,O(1)询问...

No.2单个字符串的相关问题

1、重复子串

可重叠最长重复子串:

题目:

给定一个字符串,求最长重复子串,这两个子串可以重叠。

分析:

就是height数组的最大值...

不可重叠最长重复子串(POJ1743)

题目:

给定一个字符串,求最长重复子串,这两个子串不能重叠。

这道题有一个特殊要求是如果一个子串的每个数同时加上一个相同的数字所得到的子串也在字符串中出现的话也是重复子串...

分析:

我们先忽略特殊要求只考虑普通的重复子串...

首先我们通过二分答案把最优性问题转化为可行性问题...

我们二分最长的重复字串的长度为len,然后我们根据len把sa按照height数组分组,我们把sa分成若干组,保证每一组的height最小值都大于等于len,这样就保证了组内的最长公共前缀是大于等于len的,现在要求不重复,就是要求最长公共前缀大于等于len的两个后缀的开头距离是大于等于len的,这样就保证了不重复...

现在考虑特殊要求,因为整体加数相同的话说,差分之后也应该相同,所以我们把n个数通过差分变成n-1个数,其他的照旧,只不过开头距离大于len的才合法...(因为是差分之后的...)

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
//良辰美景奈何天,赏心乐事谁家院 const int maxn=200000+5; int n,s[maxn],gs[maxn],wv[maxn],wb[maxn],sa[maxn],rank[maxn],height[maxn]; inline int read(void){
char ch=getchar();int x=0;
while(!(ch>='0'&&ch<='9'))
ch=getchar();
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
return x;
} inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:233,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
} inline bool check(int x){
int Max=0,Min=n;bool ans=0;
for(int i=2;i<=n&&ans==0;i++){
if(height[i]<x){
if(Max!=0)
if(Max-Min>x)
ans=1;
Min=Max=sa[i];
continue;
}
Max=max(Max,sa[i]),Min=min(Min,sa[i]);
}
if(Max!=0&&Max-Min>x)
ans=1;
return ans;
} signed main(void){
while(n=read()){
memset(s,0,sizeof(s));
memset(gs,0,sizeof(gs));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
memset(sa,0,sizeof(sa));
memset(rank,0,sizeof(rank));
memset(height,0,sizeof(height));
for(int i=0;i<n;i++)
s[i]=read();
if(n<10){
puts("0");continue;
}
n--;
for(int i=0;i<n;i++)
rank[i]=s[i]=s[i+1]-s[i]+100;
s[n]=0;
da(sa,rank,n+1,200);calheight(n);
int l=4,r=n>>1,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d\n",ans+1);
}
return 0;
}//Cap ou pas cap. Pas cap.

可重叠的k次最长重复子串(POJ3261)

题意:

给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠。

分析:

和上一个题一样还是利用了二分和分组的思想,我们二分答案,然后按照二分的答案分组,如果存在一组连续后缀大于等于k个就代表合法...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=20000+5; int n,len,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],ran[maxn],height[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline bool check(int x){
int cnt=0;
for(int i=1;i<=n;i++){
if(height[i]<x){
if(cnt>=len)
return true;
cnt=1;continue;
}
cnt++;
}
if(cnt>=len)
return true;
return false;
} signed main(void){
scanf("%d%d",&n,&len);
for(int i=0;i<n;i++)
scanf("%d",&s[i]),ran[i]=s[i];
da(sa,ran,n+1,n+1),calheight(n);
int l=1,r=n,ans=0;
while(l<=r){
int mid=l+r>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d\n",ans);
return 0;
}//Cap ou pas cap. Pas cap.

2.子串的个数

不相同的子串个数(spoj694,spoj705)

题目:

给定一个字符串,求不相同的子串的个数。

分析:

我们考虑每次新加入下一个后缀的时候产生的子串的贡献是n-sa[i],其中和上一个重复的是height[i]个,所以当前的后缀对答案产生的贡献是n-sa[i]-height[i]...

代码:

SPOJ694

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=1000+5; int n,cas,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],ran[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline int solve(int n){
int ans=0;
for(int i=1;i<=n;i++)
ans+=n-sa[i]-height[i];
return ans;
} signed main(void){
scanf("%d",&cas);
while(cas--){
memset(s,0,sizeof(s));
memset(gs,0,sizeof(gs));
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
memset(ran,0,sizeof(ran));
memset(height,0,sizeof(height));
scanf("%s",str);n=strlen(str);
for(int i=0;i<n;i++)
s[i]=(int)str[i]+1,ran[i]=s[i];
da(sa,ran,n+1,300);calheight(n);
printf("%d\n",solve(n));
}
return 0;
}//Cap ou pas cap. Pas cap.

SPOJ705

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=50000+5; int n,cas,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],ran[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline int solve(int n){
int ans=0;
for(int i=1;i<=n;i++)
ans+=n-sa[i]-height[i];
return ans;
} signed main(void){
scanf("%d",&cas);
while(cas--){
memset(s,0,sizeof(s));
memset(gs,0,sizeof(gs));
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
memset(ran,0,sizeof(ran));
memset(height,0,sizeof(height));
scanf("%s",str);n=strlen(str);
for(int i=0;i<n;i++)
s[i]=(int)str[i]+1,ran[i]=s[i];
da(sa,ran,n+1,300);calheight(n);
printf("%d\n",solve(n));
}
return 0;
}//Cap ou pas cap. Pas cap.

3.回文子串

最长回文子串(ural1297)

题目:

给定一个字符串,求最长回文子串。

分析:

我们考虑枚举回文子串的中心,然后其长度就是把原串反过来之后某个后缀和原串的某个后缀的最长公共前缀...然后就是RMQ问题了...

代码:

来自机房小伙伴的嘲讽:这水题为啥要写...为啥要用后缀数组写,闲的吧...

woc...我就是想练一练后缀数组,你们至于嘛QAQ...

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=2000+5; int n,t,be,ans,s[maxn],gs[maxn],sa[maxn],st[maxn][25],wb[maxn],wv[maxn],ran[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline void init(void){
for(int i=1;i<=n;i++)
st[i][0]=height[i];
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j-1)<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
} inline int query(int x,int y){
if(y<x)
swap(x,y);
x++;
int len=y-x+1,k;
for(k=20;k>=0;k--)
if(len&(1<<k)||k==0)
break;
return min(st[x][k],st[y-(1<<k)+1][k]);
} signed main(void){
scanf("%s",str);t=n=strlen(str);
for(int i=0;i<n;i++)
s[i]=(int)str[i];
s[n]=200;ans=1;be=0;
for(int i=1;i<=n;i++)
s[i+n]=s[n-i];
n<<=1,n++;
for(int i=0;i<n;i++)
ran[i]=s[i];
da(sa,ran,n+1,201);calheight(n);init();
for(int i=1;i<t-1;i++){
int a=query(ran[i+1],ran[t-i+1+t]);
if(a*2+1>ans)
ans=a*2+1,be=i-a;
a=query(ran[i],ran[t-i+1+t]);
if(a*2>ans)
ans=a*2,be=i-a;
}
if(s[t-1]==s[t-2]&&ans<2)
ans=2,be=t-2;
for(int i=1;i<=ans;i++)
printf("%c",(char)s[i+be-1]);
puts("");
return 0;
}//Cap ou pas cap. Pas cap.

4.连续重复子串

连续重复子串(POJ2406)

题目:

给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的, 求 R 的最大值。

分析:

这题解法真多...不过本质上是一样的...

枚举循环节长度len,然后判断sunffix(1)和suffix(k+1)的最长公共前缀是否等于n-k...

但是由于数据范围有点大...倍增算法过不了...必须要用DC3...TAT...所以我就TLE到死...QAQ

代码:

先放倍增的代码...DC3的代码以后补...(怎么又挖了一个坑TAT...

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=1000000+5; int n,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],ran[maxn],Min[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline int solve(void){
int i;
for(i=1;i<=n;i++)
if(sa[i]==0)
break;
if(i!=1)
Min[i-1]=height[i];
for(int j=i-2;j>=1;j--)
Min[i]=min(Min[i+1],height[i]);
if(i!=n)
Min[i+1]=height[i+1];
for(int j=i+1;j<=n;j++)
Min[i]=min(Min[i-1],height[i]);
for(i=1;i<=n;i++)
if(n%i==0&&Min[ran[i]]==n-i)
break;
return n/i;
} signed main(void){
while(scanf("%s",str)&&str[0]!='.'){
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
n=strlen(str);s[n]=0,ran[n]=0;
for(int i=0;i<n;i++)
s[i]=(int)str[i]+1,ran[i]=s[i];
da(sa,ran,n+1,300),calheight(n);
printf("%d\n",solve());
}
return 0;
}//Cap ou pas cap. Pas cap.

重复次数最多的连续重复子串(SPOJ687&POJ3693)

题目:

给定一个字符串,求重复次数最多的连续重复子串。

分析:

SPOJ的那道题比较简单。和hihocoder的解法一样...

POJ的那道题还要求字典序最小...

代码:

SPOJ687

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=100000+5; int n,cas,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],st[maxn][25],ran[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline void init(void){
for(int i=1;i<=n;i++)
st[i][0]=height[i];
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j-1)<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
} inline int lcp(int x,int y){
x=ran[x],y=ran[y];
if(x>y)
swap(x,y);
x++;
int len=y-x+1,k;
for(k=20;k>=0;k--)
if(len&(1<<k)||k==0)
break;
return min(st[x][k],st[y-(1<<k)+1][k]);
} inline int solve(void){
int ans=0;
for(int len=1;len<=n;len++)
for(int i=0;i+len<n;i+=len){
int r=lcp(i,i+len);
if(r/len+1>ans)
ans=r/len;
if(i>=len-r/len)
if(lcp(i-len+r%len,i+r%len)/len+1>ans)
ans=lcp(i-len+r%len,i+r%len)/len+1;
}
return ans;
} signed main(void){
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",str+i);
memset(s,0,sizeof(s));
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
memset(ran,0,sizeof(ran));
for(int i=0;i<n;i++)
s[i]=(int)str[i]+1,ran[i]=s[i];
da(sa,ran,n+1,300);calheight(n);init();
printf("%d\n",solve());
}
return 0;
}//Cap ou pas cap. Pas cap.

POJ3693

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std; const int maxn=100000+5; int n,cas,tail,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],st[maxn][25],ran[maxn],stk[maxn],height[maxn]; char str[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline void init(void){
for(int i=1;i<=n;i++)
st[i][0]=height[i];
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j-1)<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
} inline int lcp(int x,int y){
x=ran[x],y=ran[y];
if(x>y)
swap(x,y);
x++;
int len=y-x+1,k;
for(k=20;k>=0;k--)
if(len&(1<<k)||k==0)
break;
return min(st[x][k],st[y-(1<<k)+1][k]);
} inline void solve(void){
int ans=0,be=-1,en;
for(int len=1;len<=n;len++)
for(int i=0;i+len<n;i+=len){
int r=lcp(i,i+len);
if(r/len+1>ans)
ans=r/len,stk[tail=1]=len;
else if(r/len+1==ans&&stk[tail]!=len)
stk[++tail]=len;
if(i>=len-r/len){
int lala=lcp(i-len+r%len,i+r%len);
if(lala/len+1>ans)
ans=lala/len+1,stk[tail=1]=len;
else if(lala/len+1==ans&&stk[tail]!=len)
stk[++tail]=len;
}
}
for(int i=1;i<=n&&be==-1;i++)
for(int j=1;j<=tail&&be==-1;j++)
if(lcp(sa[i],sa[i]+stk[j])/stk[j]+1==ans)
be=sa[i],en=sa[i]+ans*stk[j];
for(int i=be;i<en;i++)
printf("%c",str[i]);
puts("");
} signed main(void){
while(scanf("%s",str)&&str[0]!='#'){
cas++;tail=0;
memset(s,0,sizeof(s));
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wv,0,sizeof(wv));
memset(ran,0,sizeof(ran));
n=strlen(str);printf("Case %d: ",cas);
for(int i=0;i<n;i++)
s[i]=(int)str[i]+1,ran[i]=s[i];
da(sa,ran,n+1,300);calheight(n);init();solve();
}
return 0;
}//Cap ou pas cap. Pas cap.

No.3两个字符串的相关问题

1.公共子串

最长公共子串(POJ2774&ural1517)

题解

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
//zhao kan fei niao mu fei hui,ying chuang hua luo lian chui di const int maxn=200000+5; int n,t,s[maxn],gs[maxn],sa[maxn],wb[maxn],wv[maxn],ran[maxn],height[maxn]; char s1[maxn],s2[maxn]; inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
} inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
} inline void calheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
} inline int solve(int n){
int ans=0;
for(int i=1;i<=n;i++)
if((sa[i]<t&&sa[i-1]>t)||(sa[i]>t&&sa[i-1]<t))
ans=max(ans,height[i]);
return ans;
} signed main(void){
scanf("%s%s",s1,s2);t=n=strlen(s1);
for(int i=0;i<n;i++)
s[i]=s1[i]-'a'+1;
s[n]=100;int lala=strlen(s2);
for(int i=1;i<=lala;i++)
s[i+n]=s2[i-1]-'a'+1;n+=lala+1;
for(int i=0;i<n;i++)
ran[i]=s[i];
da(sa,ran,n+1,101);
calheight(n);
printf("%d\n",solve(n));
return 0;
}//Cap ou pas cap. Pas cap.

By NeighThorn

后缀数组基本问题QAQ的更多相关文章

  1. 【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

    4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status] ...

  2. Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Sub ...

  3. [bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)

    以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列S ...

  4. 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)

    模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...

  5. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  6. POJ2406 Power Strings 【KMP 或 后缀数组】

    电源串 时间限制: 3000MS   内存限制: 65536K 提交总数: 53037   接受: 22108 描述 给定两个字符串a和b,我们定义a * b是它们的连接.例如,如果a =" ...

  7. [poj 3693]后缀数组+出现次数最多的重复子串

    题目链接:http://poj.org/problem?id=3693 枚举长度L,看长度为L的子串最多能重复出现几次,首先,能出现1次是肯定的,然后看是否能出现两次及以上.由抽屉原理,这个子串出现次 ...

  8. 【距离GDOI:136天】 后缀数组中...

    当时后缀数组没有好好学...各种应用都没学,这两天好好补,要把罗神的论文好好研究一遍...其实后缀数组真的好神奇!!特别是那个萌萌的height数组! 今天终于能有两节完整的晚自修了QAQ...明晚还 ...

  9. POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题

    POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 ...

随机推荐

  1. 爬虫学习(八)——带cookie的网页进行爬取

    # 前提:# # 通常,很多网站需要登录才能进行浏览,所以在爬取这些网站时,也需要进行登录,并拿取登录时的cookie# # 登录网页,服务器会给客户端一个牌子cookie# # 访问登录页面时,带着 ...

  2. Freemaker基于word模板动态导出压缩文件汇总整理

    Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...

  3. CSS+JS实现流星雨动画

    引言 平常会做一些有意思的小案例练手,通常都会发到codepen上,但是codepen不能写分析.        所以就在博客上开个案例分享系列,对demo做个剖析.目的以分享为主,然后也希望各路大神 ...

  4. linux的发展过程

    1. 操作系统 人与计算机硬件直接的中介 2. Linux系统组成 3. Linux的发展过程 蛋-人-人-人 unix于诞生贝尔实验室 人-谭教授 谭宁邦 minix mini unix. 主要用于 ...

  5. 问题 B: 分组统计

    分组统计 问题 B: 分组统计时间限制: 1 Sec 内存限制: 32 MB 提交: 416 解决: 107 [提交][状态][讨论版][命题人:外部导入] 题目描述 先输入一组数,然后输入其分组,按 ...

  6. Linux系统软件包之---Apache

    当前互联网主流web服务说明 静态服务: apache 中小型静态web服务的主流,web服务器中的老大哥 nginx 大型新兴网站静态web服务主流,web服务器中的初生牛犊 lighttpd 静态 ...

  7. opencv使用日记之一:平台搭建Mat类以及图像的读取修改

    平台搭建就摸了一整天时间,真的是...不说了,最后我选择的是 opencv3.0(2015/06/04)  + win7 + vs2012   注意opencv的版本不同导入的库文件是不一样的,所以请 ...

  8. 线程、进程、队列、IO多路模型

    操作系统工作原理介绍.线程.进程演化史.特点.区别.互斥锁.信号.事件.join.GIL.进程间通信.管道.队列.生产者消息者模型.异步模型.IO多路复用模型.select\poll\epoll 高性 ...

  9. Hyper-V:利用差异磁盘安装多个Win2008

    签于成本的原因,在学习了解一项新的技术或是产品时,在没有部署到生产环境之中前,大家都会选择在虚拟机来搭建一套实验环境.但如何快速搭建呢?如何节省磁盘空间呢? 说到此都不得不说下Hyper-V的差异磁盘 ...

  10. 微信公众开发api接口

      简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器 ...