题目:
http://codevs.cn/problem/3160/
分析:
若n在10000以内,可以O(n^2) dp;
即:f[i][j]= f[i-1][j-1] +1 , s[i]==t[j]
= 0 , s[i]!=t[j]
这里是最长公共子串,要注意跟子序列区分开,
子序列在s[i] != t[j]时是f[i][j] = max( f[i-1][j] , f[i][j-1] );
但这个题目n=100000,需要用后缀数组求解。
两个串怎么应用后缀数组呢?那么就是用一个没出现过的字符‘#’连接成一个串;
(高度数组)lcp[i] 表示sa[rank[i]-1]和sa[rank[i]]的最长公共子串;
代码:
①sort版
#include <bits/stdc++.h>
using namespace std;
const int Tmax=100005;
string s,t,A;
int sa[Tmax*2],rank[Tmax*2],tmp[Tmax*2],lcp[Tmax*2];
int k,n;
bool cmp(int i,int j)
{
if(rank[i]!=rank[j]) return rank[i]<rank[j];
int ri=i+k<=n?rank[i+k]:-1;
int rj=j+k<=n?rank[j+k]:-1;
return ri<rj;
}
void suffix()
{
n=A.length();
for(int i=0;i<=n;i++)
{
sa[i]=i;
rank[i]=i<n?A[i]:-1;
}
for(k=1;k<=n;k*=2)
{
sort(sa,sa+1+n,cmp);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++)
{
tmp[sa[i]]=tmp[sa[i-1]];
if(cmp(sa[i-1],sa[i])==true) tmp[sa[i]]++;
}
for(int i=0;i<=n;i++)
rank[i]=tmp[i];
}
return;
}
void get_lcp()
{
int i,j,h=0;
for(i=0;i<=n;i++)
{
if(h>0) h--;
j=sa[rank[i]-1];
while(i+h<=n-1&&j+h<=n-1&&A[i+h]==A[j+h]) h++;
lcp[rank[i]]=h;
}
return;
}
int main()
{
cin>>s>>t;
A=s+'#'+t;
suffix();
get_lcp();
int ans=0;
for(int i=1;i<=n;i++)
if(((sa[i]<s.length())+(sa[i-1]<s.length()))==1)
ans=max(ans,lcp[i]);
cout<<ans;
return 0;
}
②基数排序版
#include <bits/stdc++.h>
using namespace std;
const int tmax=200005;
int len,t1[tmax],t2[tmax],c[tmax],sa[tmax],rank[tmax],height[tmax];
char s[tmax];
int k,la;
bool cmp(int *y,int i,int j)
{
if(y[i]!=y[j]) return y[i]<y[j];
int ri=i+k<=len?y[i+k]:-1;
int rj=j+k<=len?y[j+k]:-1;
return ri<rj;
}
void suffix()
{
int *x=t1,*y=t2,m=256;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<len;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=len-1;i>=0;i--) sa[--c[x[i]]]=i;
for(k=1;k<len;k<<=1)
{
int p=0;
for(int i=len-k;i<len;i++) y[p++]=i;
for(int i=0;i<len;i++)
if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<len;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=len-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
m=1;x[sa[0]]=0;
for(int i=1;i<len;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i])==true? m++:m-1;
if(m>=len) break;
}
return;
}
void get_height()
{
int i,j,h=0;
for(i=0;i<len;i++) rank[sa[i]]=i;
height[0]=0;
for(i=0;i<len;i++)
{
if(rank[i]==0) continue;
j=sa[rank[i]-1];
if(h>0) h--;
while(i+h<len&&j+h<len&&s[i+h]==s[j+h]&&s[i+h]!='~'&&s[j+h]!='~') h++;
height[rank[i]]=h;
}
return;
}
void work()
{
int ans=0,i;
for(i=0;i<=len;i++)
if(((sa[i]<la)+(sa[i-1]<la))==1)
ans=max(ans,height[i]);
cout<<ans;
return;
}
int main()
{
scanf("%s",s);
la=strlen(s);
s[la]='~';
scanf("%s",s+la+1);
len=strlen(s);
suffix();
get_height();
work();
return 0;
}
蒟蒻的庆祝