1.模板
2.ural1517最长公共子串
3.ural1297最长回文子串
4.spoj705不相同的子串的个数
5.spoj694不相同的子串的个数
6.spoj687重复次数最多的连续重复子串
7.spoj220每个字符串至少出现两次且不重叠的最长子串
8.pku3415长度不小于k 的公共子串的个数
9.pku3294不小于k 个字符串中的最长子串
10.pku3261可重叠的k 次最长重复子串
11.pku2774最长公共子串
12.pku1743不可重叠最长重复子串
13.pku1226
1.模板
#define maxn 1000001
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int RMQ[maxn];
int mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
int i,j,a,b;
for(mm[0]=-1,i=1;i<=n;i++)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
for(i=1;i<=n;i++) best[0][i]=i;
for(i=1;i<=mm[n];i++)
for(j=1;j<=n+1-(1<<i);j++)
{
a=best[i-1][j];
b=best[i-1][j+(1<<(i-1))];
if(RMQ[a]<RMQ[b]) best[i][j]=a;
else best[i][j]=b;
}
return;
}
int askRMQ(int a,int b)
{
int t;
t=mm[b-a+1];b-=(1<<t)-1;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b)
{
int t;
a=rank[a];b=rank[b];
if(a>b) {t=a;a=b;b=t;}
return(height[askRMQ(a+1,b)]);
}
2.ural1517最长公共子串
给定两个字符串A 和B,求最长公共子串。
#include "stdio.h"
#define maxn 200002
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
char s[maxn];
int r[maxn],sa[maxn];
int main()
{
int i,j,n,ans=0,w;
scanf("%d",&j);
scanf("%s",s);
s[j]=1;
scanf("%s",s+j+1);
n=j+j+1;
for(i=0;i<n;i++) r[i]=s[i];
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
for(i=2;i<=n;i++)
if(height[i]>ans)
if((j<sa[i-1] && j>sa[i])
|| (j>sa[i-1] && j<sa[i])) ans=height[i],w=sa[i];
s[w+ans]=0;
printf("%s\n",s+w);
return 0;
}
3.ural1297最长回文子串
给定一个字符串,求最长回文子串。
#include "stdio.h"
#include "string.h"
#define maxn 2002
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int RMQ[maxn];
int mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
int i,j,a,b;
for(mm[0]=-1,i=1;i<=n;i++)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
for(i=1;i<=n;i++) best[0][i]=i;
for(i=1;i<=mm[n];i++)
for(j=1;j<=n+1-(1<<i);j++)
{
a=best[i-1][j];
b=best[i-1][j+(1<<(i-1))];
if(RMQ[a]<RMQ[b]) best[i][j]=a;
else best[i][j]=b;
}
return;
}
int askRMQ(int a,int b)
{
int t;
t=mm[b-a+1];b-=(1<<t)-1;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b)
{
int t;
a=rank[a];b=rank[b];
if(a>b) {t=a;a=b;b=t;}
return(height[askRMQ(a+1,b)]);
}
char st[maxn];
int r[maxn],sa[maxn];
int main()
{
int i,n,len,k,ans=0,w;
scanf("%s",st);
len=strlen(st);
for(i=0;i<len;i++) r[i]=st[i];
r[len]=1;
for(i=0;i<len;i++) r[i+len+1]=st[len-1-i];
n=len+len+1;
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
for(i=1;i<=n;i++) RMQ[i]=height[i];
initRMQ(n);
for(i=0;i<len;i++)
{
k=lcp(i,n-i);
if(k*2>ans) ans=k*2,w=i-k;
k=lcp(i,n-i-1);
if(k*2-1>ans) ans=k*2-1,w=i-k+1;
}
st[w+ans]=0;
printf("%s\n",st+w);
return 0;
}
4.spoj705不相同的子串的个数
给定一个字符串,求不相同的子串的个数。
#include "stdio.h"
#include "string.h"
#define maxn 50001
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
char s[maxn];
int r[maxn],sa[maxn];
int main()
{
int i,n,t;
long long ans;
scanf("%d",&t);
while(t-->0)
{
scanf("%s",s);
n=strlen(s);
for(i=0;i<n;i++) r[i]=s[i];
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
ans=(long long)n*(n+1)/2;
for(i=1;i<=n;i++) ans-=height[i];
printf("%lld\n",ans);
}
return 0;
}
5.spoj694不相同的子串的个数
给定一个字符串,求不相同的子串的个数。
#include "stdio.h"
#include "string.h"
#define maxn 1001
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
char s[maxn];
int r[maxn],sa[maxn];
int main()
{
int i,n,t,ans;
scanf("%d",&t);
while(t-->0)
{
scanf("%s",s);
n=strlen(s);
for(i=0;i<n;i++) r[i]=s[i];
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
ans=n*(n+1)/2;
for(i=1;i<=n;i++) ans-=height[i];
printf("%d\n",ans);
}
return 0;
}
6.spoj687重复次数最多的连续重复子串
给定一个字符串,求重复次数最多的连续重复子串。
#include "stdio.h"
#define maxn 50001
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int RMQ[maxn];
int mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
int i,j,a,b;
for(mm[0]=-1,i=1;i<=n;i++)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
for(i=1;i<=n;i++) best[0][i]=i;
for(i=1;i<=mm[n];i++)
for(j=1;j<=n+1-(1<<i);j++)
{
a=best[i-1][j];
b=best[i-1][j+(1<<(i-1))];
if(RMQ[a]<RMQ[b]) best[i][j]=a;
else best[i][j]=b;
}
return;
}
int askRMQ(int a,int b)
{
int t;
t=mm[b-a+1];b-=(1<<t)-1;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b)
{
int t;
a=rank[a];b=rank[b];
if(a>b) {t=a;a=b;b=t;}
return(height[askRMQ(a+1,b)]);
}
char c;
int r[maxn],sa[maxn];
int main()
{
int i,j,jj,k,n,now,ans,nn;
scanf("%d\n",&nn);
while(nn-->0)
{
scanf("%d\n",&n);
for(i=0;i<n;i++)
{
scanf("%c\n",&c);
r[i]=c;
}
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
for(i=1;i<=n;i++) RMQ[i]=height[i];
initRMQ(n);
ans=0;
for(i=1;i<n;i++)
{
for(j=0;j+i<n;j+=i)
{
k=lcp(j,j+i);
now=k/i;
jj=j-(i-k%i);
if(jj>=0)
if(lcp(jj,jj+i)>=(i-k%i)) now++;
if(now>ans) ans=now;
}
}
printf("%d\n",ans+1);
}
return 0;
}
7.spoj220每个字符串至少出现两次且不重叠的最长子串
给定n 个字符串,求在每个字符串中至少出现两次且不重叠的最长子串。
#include "stdio.h"
#include "string.h"
#define maxn 100011
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int r[maxn],sa[maxn];
int who[maxn],min[11],max[11];
int len,n;
int check(int mid)
{
int i,j,k;
for(i=2;i<=len;i=j+1)
{
for(;height[i]<mid && i<=len;i++);
for(j=i;height[j]>=mid;j++);
if(j-i+1<n) continue;
for(k=1;k<=n;k++) {min[k]=1000000;max[k]=-1;}
for(k=i-1;k<j;k++)
{
if(sa[k]<min[who[sa[k]]]) min[who[sa[k]]]=sa[k];
if(sa[k]>max[who[sa[k]]]) max[who[sa[k]]]=sa[k];
}
for(k=1;k<=n;k++) if(max[k]-min[k]<mid) break;
if(k>n) return 1;
}
return 0;
}
char st[110];
int main()
{
int i,j,k,min,mid,max,nn;
scanf("%d",&nn);
while(nn-->0)
{
scanf("%d",&n);
len=0;
for(i=1;i<=n;i++)
{
scanf("%s",st);
k=strlen(st);
for(j=0;j<k;j++)
{
r[j+len]=st[j]+10;
who[j+len]=i;
}
r[len+k]=i;
who[len+k]=0;
len+=k+1;
}
len--;
r[len]=0;
da(r,sa,len+1,138);
calheight(r,sa,len);
height[len+1]=-1;
min=1;max=5000;
while(min<=max)
{
mid=(min+max)>>1;
if(check(mid)) min=mid+1;
else max=mid-1;
}
printf("%d\n",max);
}
return 0;
}
8.pku3415长度不小于k 的公共子串的个数
给定两个字符串A 和B,求长度不小于k 的公共子串的个数(可以相同)。
样例1:
A=“xx”,B=“xx”,k=1,长度不小于k 的公共子串的个数是5。
样例2:
A =“aababaa”,B =“abaabaa”,k=2,长度不小于k 的公共子串的个数是22。
#include "stdio.h"
#include "string.h"
#define maxn 200002
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int r[maxn],sa[maxn];
char s[maxn];
int f[maxn];
int a[maxn],b[maxn],c;
long long ss,ans;
int main()
{
int i,k,l,n,t;
scanf("%d",&k);
while(k!=0)
{
scanf("%s",s);
l=strlen(s);
s[l]=1;
scanf("%s",s+l+1);
n=strlen(s);
for(i=0;i<n;i++) r[i]=s[i];
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
for(i=2;i<=n;i++)
{
f[i]=sa[i]<l;
height[i]-=k-1;
if(height[i]<0) height[i]=0;
}
height[n+1]=0;
a[0]=-1;ans=0;
for(t=0;t<=1;t++)
for(c=0,ss=0,i=2;i<=n;i++)
{
if(f[i]!=t) ans+=ss;
c++;
a[c]=height[i+1];
b[c]=f[i]==t;
ss+=(long long)a[c]*b[c];
while(a[c-1]>=a[c])
{
ss-=(long long)(a[c-1]-a[c])*b[c-1];
a[c-1]=a[c];
b[c-1]+=b[c];
c--;
}
}
printf("%I64d\n",ans);
scanf("%d",&k);
}
return 0;
}
9.pku3294不小于k 个字符串中的最长子串
给定n 个字符串,求出现在不小于k 个字符串中的最长子串。
算法分析:
将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,
求后缀数组。然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组
的后缀是否出现在不小于k 个的原串中。这个做法的时间复杂度为O(nlogn)。
#include "stdio.h"
#include "string.h"
#define maxn 100101
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int r[maxn],sa[maxn];
int who[maxn],yes[101]={0},ii=0;
int len,n,nn;
int ans[maxn],ss;
int check(int mid)
{
int i,j,k,t,s,flag=0;
for(i=2;i<=len;i=j+1)
{
for(;height[i]<mid && i<=len;i++);
for(j=i;height[j]>=mid;j++);
if(j-i+1<nn) continue;
ii++;s=0;
for(k=i-1;k<j;k++)
if((t=who[sa[k]])!=0)
if(yes[t]!=ii) yes[t]=ii,s++;
if(s>=nn) if(flag) ans[++ss]=sa[i-1];
else ans[ss=1]=sa[i-1],flag=1;
}
return(flag);
}
char st[1010];
int main()
{
int i,j,k,flag=0,min,mid,max;
scanf("%d",&n);
while(n!=0)
{
len=0;
for(i=1;i<=n;i++)
{
scanf("%s",st);
k=strlen(st);
for(j=0;j<k;j++)
{
r[j+len]=st[j]+100;
who[j+len]=i;
}
r[len+k]=i;
who[len+k]=0;
len+=k+1;
}
len--;
r[len]=0;
da(r,sa,len+1,227);
calheight(r,sa,len);
height[len+1]=-1;
nn=n/2+1;
min=1;max=1000;
while(min<=max)
{
mid=(min+max)>>1;
if(check(mid)) min=mid+1;
else max=mid-1;
}
if(flag) printf("\n");
else flag=1;
if(max==0) printf("?\n");
else for(i=1;i<=ss;i++)
{
k=ans[i];
for(j=0;j<max;j++) printf("%c",r[k+j]-100);
printf("\n");
}
scanf("%d",&n);
}
return 0;
}
10.pku3261可重叠的k 次最长重复子串
给定一个字符串,求至少出现k 次的最长重复子串,这k 个子串可以重叠。
算法分析:
这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组。不
同的是,这里要判断的是有没有一个组的后缀个数不小于k。如果有,那么存在
k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为O(nlogn)。
#include "stdio.h"
#define maxn 20001
#define maxm 1000002
int wa[maxn],wb[maxn],wv[maxn],ws[maxm];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int check(int n,int k,int mid)
{
int i,s=1;
for(i=1;i<=n;i++)
if(height[i]>=mid)
{
s++;
if(s>=k) return(1);
}
else s=1;
return(0);
}
int r[maxn],sa[maxn];
int main()
{
int i,k,n;
int min,mid,max;
scanf("%d %d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&r[i]);
r[i]++;
}
r[n]=0;
da(r,sa,n+1,1000002);
calheight(r,sa,n);
min=1;max=n;
while(min<=max)
{
mid=(min+max)/2;
if(check(n,k,mid)) min=mid+1;
else max=mid-1;
}
printf("%d\n",max);
return 0;
}
11.pku2774最长公共子串
给定两个字符串A 和B,求最长公共子串。
#include "stdio.h"
#include "string.h"
#define maxn 200002
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
char s[maxn];
int r[maxn],sa[maxn];
int main()
{
int i,j,n,ans=0;
scanf("%s",s);
j=strlen(s);
s[j]=1;
scanf("%s",s+j+1);
n=strlen(s);
for(i=0;i<n;i++) r[i]=s[i];
r[n]=0;
da(r,sa,n+1,128);
calheight(r,sa,n);
for(i=2;i<=n;i++)
if(height[i]>ans)
if((j<sa[i-1] && j>sa[i])
|| (j>sa[i-1] && j<sa[i])) ans=height[i];
printf("%d\n",ans);
return 0;
}
12.pku1743不可重叠最长重复子串
给定一个字符串,求最长重复子串,这两个子串不能重叠。
#include "stdio.h"
#define maxn 20000
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int check(int *sa,int n,int k)
{
int i,max=sa[1],min=sa[1];
for(i=2;i<=n;i++)
{
if(height[i]<k) max=min=sa[i];
else
{
if(sa[i]<min) min=sa[i];
if(sa[i]>max) max=sa[i];
if(max-min>k) return(1);
}
}
return(0);
}
int r[maxn],sa[maxn];
int main()
{
int i,j=0,k,n;
int min,mid,max;
scanf("%d",&n);
while(n!=0)
{
n--;
scanf("%d",&j);
for(i=0;i<n;i++)
{
scanf("%d",&k);
r[i]=k-j+100;
j=k;
}
r[n]=0;
da(r,sa,n+1,200);
calheight(r,sa,n);
min=1;max=n/2;
while(min<=max)
{
mid=(min+max)/2;
if(check(sa,n,mid)) min=mid+1;
else max=mid-1;
}
if(max>=4) printf("%d\n",max+1);
else printf("0\n");
scanf("%d",&n);
}
return 0;
}
13.pku1226
#include "stdio.h"
#include "string.h"
#define maxn 20201
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;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++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int r[maxn],sa[maxn];
int who[maxn],yes[101]={0},ii=0;
int len,n;
int check(int mid)
{
int i,j,k,t,s;
for(i=2;i<=len;i=j+1)
{
for(;height[i]<mid && i<=len;i++);
for(j=i;height[j]>=mid;j++);
if(j-i+1<n) continue;
ii++;s=0;
for(k=i-1;k<j;k++)
if((t=who[sa[k]])!=0)
if(yes[t]!=ii) yes[t]=ii,s++;
if(s>=n) return 1;
}
return 0;
}
char st[110];
int main()
{
int i,j,k,min,mid,max,nn;
scanf("%d",&nn);
while(nn-->0)
{
scanf("%d",&n);
len=0;
for(i=1;i<=n;i++)
{
scanf("%s",st);
k=strlen(st);
for(j=0;j<k;j++)
{
r[j+len]=st[j]+200;
who[j+len]=i;
}
r[len+k]=2*i-1;
who[len+k]=0;
len+=k+1;
for(j=0;j<k;j++)
{
r[j+len]=st[k-1-j]+200;
who[j+len]=i;
}
r[len+k]=2*i;
who[len+k]=0;
len+=k+1;
}
len--;
r[len]=0;
da(r,sa,len+1,328);
calheight(r,sa,len);
height[len+1]=-1;
min=1;max=100;
while(min<=max)
{
mid=(min+max)>>1;
if(check(mid)) min=mid+1;
else max=mid-1;
}
if(n==1) max=len/2;
printf("%d\n",max);
}
return 0;
}