pku2774 求最长公共子串
嘿嘿,用大牛的代码过的,我觉得,要理解这个好难呀,但要是用了模板计算后缀数组sa[],名次数组rank[],还有height[],height[]是后缀数组的关键所在,用来模板计算出这三个数组,后缀数组的应用也就拓展得开了哦
看下模板吧,不过这个版本用了657ms耶,不是很快的说
#include <iostream>
using namespace std;
#define MAXN 200010// max{str.len,256}
int b[MAXN],array[4][MAXN],*rank1,*nrank,*sa,*nsa,height[MAXN],n,len;
char str[MAXN],str1[MAXN/2];
void make_sa(){
int i,k;
n=strlen(str);
sa=array[0];
nsa=array[1];
rank1=array[2];
nrank=array[3];
//求sa_1
//计数排序
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
b[str[i]]++;
for(i=1;i<=256;i++)
b[i]+=b[i-1];
for(i=n-1;i>=0;i--)//str[i]
sa[--b[str[i]]]=i;
//求rank_1
for(rank1[sa[0]]=0,i=1;i<n;i++){//sa[i]
rank1[sa[i]]=rank1[sa[i-1]];
if(str[sa[i]]!=str[sa[i-1]])
rank1[sa[i]]++;
}
for(k=1;k<n && rank1[sa[n-1]]<n-1;k*=2){
//求sa_2k
//桶排序
//只保存每个桶的尾部后缀的编号作为索引(编号为i的后缀即suffix(sa[i]))。
//注意到在sa_n和rank_n构造完毕之前,sa_k和rank_k不一定是互为反函数:
//sa-k[i]=j总是双射;rank-k[i]=j可能存在多个i映射到一个j上。
//反映到算法上就是所有k前缀相等的后缀都放在一个桶内。
for(i=0;i<n;i++)//sa[i]
b[rank1[sa[i]]]=i;
//基数排序
//由于2k前缀的后半段已排好序,对所有后缀的2k前缀的排序结果就是对2k前缀
//的前半段的稳定排序结果。
//注意到一个后缀的2k前缀的前半段实质是某一个后缀的k前缀,所有后缀的k前
//缀的排序结果已由桶排得到
for(i=n-1;i>=0;i--)//sa[i]
if(sa[i]-k>=0)
nsa[b[rank1[sa[i]-k]]--]=sa[i]-k;
//长度不足2k的后缀的编号不变
for(i=n-k;i<n;i++)//i=sa[j]
nsa[b[rank1[i]]--]=i;
//求rank_2k
for(nrank[nsa[0]]=0,i=1;i<n;i++){//nsa[i]
nrank[nsa[i]]=nrank[nsa[i-1]];
//仅当两个2k前缀的前半部分和后半部分分别对应相等时两个2k前缀相等
if(rank1[nsa[i]]!=rank1[nsa[i-1]] || rank1[nsa[i]+k]!=rank1[nsa[i-1]+k])
nrank[nsa[i]]++;
}
int *t=sa;sa=nsa;nsa=t;
t=rank1;rank1=nrank;nrank=t;
}
}
void cal_height(){//height[i]定义为LCP(i-1,i),表示名次为i-1和名次为i的后缀的lcp
int i,j,k;
//rank和sa互为反函数
for(i=0,k=0;i<n;i++){//str[i]
if(rank1[i]==0)
height[rank1[i]]=0;
else{
for(j=sa[rank1[i]-1];str[i+k]==str[j+k];k++);
height[rank1[i]]=k;//k为当前h[sa[i]]的值
if(k>0)
k--;
}
}
}
int main(){
int i,p1,p2,ans;
while(scanf("%s%s",str,str1)!=EOF){
//构造"str#str1$"
len=strlen(str);
str[len]='#';
str[len+1]='\0';
strcat(str,str1);
n=strlen(str);
str[n++]='$';
str[n]='\0';
make_sa();
cal_height();
ans=0;
for(i=1;i<n;i++){
if(sa[i]<len)
p1=1;
else
p1=-1;
if(sa[i-1]<len)
p2=1;
else
p2=-1;
if(p1*p2<1 && height[i]>ans)
ans=height[i];
}
printf("%d\n",ans);
}
return 0;
}
另一个模板哦,更快一点
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int const N= 201000;
int wa[N], wb[N], ws[N], wv[N];
int sa[N], height[N], rank[N], n,r[N];
char str[N],str1[N];
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];
t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0;
for( i= 1; i< n; ++i )
x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++;
}
}
void callheight( 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++ );
}
int main(){
int i,p1,p2,ans,len1,len2;
while(scanf("%s%s",str,str1)!=EOF){
len1=strlen(str);
for(i=0;i<len1;i++)
r[i]=static_cast<int>(str[i]);
r[len1]=1;
len2=strlen(str1);
for(i=0;i<len2;i++)
r[len1+i+1]=static_cast<int>(str1[i]);
r[len1+len2+1]=0;
da(r,sa,len1+len2+2,256);
callheight(r,sa,len1+len2+1);
ans=0;
n=len1+len2+1;
for(i=1;i<=n;i++){
if(sa[i]<len1)
p1=1;
else
p1=-1;
if(sa[i-1]<len1)
p2=1;
else
p2=-1;
if(p1*p2<1 && height[i]>ans)
ans=height[i];
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号