BZOJ 2946 [Poi2000]公共串 后缀数组

题意:链接方法:后缀数组解析:首先我们把所有的字符串都链接起来,并且中间加上随意的不同间隔符,加这个是为了防止两个串连接起来对height数组造成影响。然后我们只需要搞出来height数组。然后我们需要二分一个答案即可。验证这个答案是否合理的充要条件是存在一段连续的height值,,使得这部分的所有height值均大于该答案。并且该部分包含了所有字符串。包含该字符串的定义是该字符串有一个后缀存在于该部分中。代码:;int n;int cnt[N],sa[N],t0[N],t1[N],rnk[N],height[N];char s[N];void getsa(int m){int *x=t0,*y=t1;for(int i=0;i<m;i++)cnt[i]=0;for(int i=0;i<n;i++)cnt[x[i]=s[i]]++;for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];for(int i=n-1;i>=0;i–)sa[–cnt[x[i]]]=i;for(int k=1;k<=n;k<<=1){int p=0;for(int i=n-k;i<n;i++)y[p++]=i;for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;for(int i=0;i<m;i++)cnt[i]=0;for(int i=0;i<n;i++)cnt[x[y[i]]]++;for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];for(int i=n-1;i>=0;i–)sa[–cnt[x[y[i]]]]=y[i];swap(x,y);p=1,x[sa[0]]=0;for(int i=1;i<n;i++)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&sa[i]+k<n&&sa[i-1]+k<n&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;if(p==n)break;m=p;}}void getheight(){int k=0;for(int i=0;i<n;i++)rnk[sa[i]]=i;for(int i=0;i<n;i++){if(k!=0)k–;if(!rnk[i])continue;int j=sa[rnk[i]-1];while(s[i+k]==s[j+k])k++;height[rnk[i]]=k;}}int t;int belong[N];int hash[6];bool check(int x){for(int la=1,i=1;i<=n+1;i++){if(height[i]<x||i==n+1){for(int j=1;j<=t;j++)hash[j]=0;for(int j=la;j<=i-1;j++)hash[belong[sa[j]]]=1;int flag=0;for(int j=1;j<=t;j++)if(hash[j]==0){flag=1;break;}if(!flag)return 1;la=i;}}return 0;}int main(){scanf(“%d”,&t);int tmp=0;for(int i=1;i<=t;i++){s[tmp++]=’z’+i;scanf(“%s”,s+tmp);tmp=strlen(s);}n=tmp;s[n++]=’ ‘;int ccc=0;for(int i=0;i<tmp;i++){if(s[i]<‘a’||s[i]>’z’)ccc++;else belong[i]=ccc;}getsa(256);getheight();int l=0,r=n;int ans;while(l<=r){int mid=(l+r)>>1;if(check(mid)){ans=mid;l=mid+1;}else r=mid-1;}printf(“%d\n”,ans); }

任何的限制,都是从自己的内心开始的。

BZOJ 2946 [Poi2000]公共串 后缀数组

相关文章:

你感兴趣的文章:

标签云: