POJ 2774

来源:互联网 发布:知乎 正常感情浓度 编辑:程序博客网 时间:2024/03/29 19:38
用后缀数组求最长前缀
#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <string>#include <math.h>#define MAXN 200010using namespace std;int m1[MAXN],m2[MAXN];char s[2*MAXN];int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n;void Build_Sa(int n){//m是基数排序字符的长度 int m;int i,*x=t,*y=t2;m=(n<256?256:n);//基数排序for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[i]=s[i]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(int k=1;k<=n;k<<=1){int p=0;//直接利用sa数组排序第二关键字for(i=n-k;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;//基数排序第一关键字for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=0;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];//根据sa和y数组计算新的x数组swap(x,y);p=1;x[sa[0]]=0;for(i=1;i<n;i++)x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;if(p>=n) break;//以后即使继续倍增,sa也不会改变,退出下次基数排序的最大值 m=p;//这个m是一直在变的,所以m只需要给出第一次基数排序的长度就可以了           }}int rank[MAXN],height[MAXN];void getHeight(int n){int i,j,k=0;for(i=0;i<n;i++) rank[sa[i]]=i;for(i=0;i<n;i++){if(k) k--; j=sa[rank[i]-1];while(s[i+k]==s[j+k]) k++;height[rank[i]]=k;}}int main(){int m,n,i,j,k,l1,l2;char str2[MAXN];while(scanf("%s%s",s,str2)!=EOF){//构造"str#str1"        l1=strlen(s);        l2=strlen(str2);        strcat(s,"*");        strcat(s,str2);        n=strlen(s);puts(s);Build_Sa(n);getHeight(n);int p,q,ans;for(i=1,ans=0;i<n;i++){/*if(sa[i]-l2>=0) p=1;else p=-1;if(sa[i-1]-l2<0) q=1;else q=-1;弄清楚sa数组里面的含义http://www.nocow.cn/index.php/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84 */if((__int64)(sa[i]-l1)*(sa[i-1]-l1)<0 && ans<height[i]) ans=height[i];}printf("%d\n",ans);}}

原创粉丝点击