题目大意:
求出在m个串中出现过大于m/2次的子串。
思路分析:
如果你只是直接跑一次后缀数组,然后二分答案扫描的话。
那么就试一下下面这个数据。
2
abcdabcdefgh
efgh
这个数据应该输出
efgh
问题就在于对于每一个串,都只能参与一次计数,所以在check的时候加一个标记数组是正解。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <map> #include <string> #define maxn 1100005 using namespace std; int str[maxn]; int sa[maxn],t1[maxn],t2[maxn],c[maxn],n; void suffix(int m) { int *x=t1,*y=t2; for(int i=0; i<m; i++)c[i]=0; for(int i=0; i<n; i++)c[x[i]=str[i]]++; for(int i=1; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[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++)c[i]=0; for(int i=0; i<n; i++)c[x[y[i]]]++; for(int i=0; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[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-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; m=p; } } int rank[maxn],height[maxn]; void getheight() { int k=0; for(int i=0; i<n; i++)rank[sa[i]]=i; for(int i=0; i<n; i++) { if(k)k--; if(!rank[i])continue; int j=sa[rank[i]-1]; while(str[i+k]==str[j+k])k++; height[rank[i]]=k; } } char tmp[1111]; int len[111]; int index[maxn]; bool vis[111]; bool check(int flen,int k,bool out) { memset(vis,false,sizeof vis); int cnt=0; for(int i=1; i<n; i++) { if(height[i]<flen) { if(out && cnt>k/2) { for(int j=sa[i-1];j<sa[i-1]+flen ; j++) printf("%c",str[j]+'a'-1); puts(""); } cnt=0; memset(vis,false,sizeof vis); } else { if(!vis[index[sa[i-1]]]) { vis[index[sa[i-1]]]=true; cnt++; } if(!vis[index[sa[i]]]) { vis[index[sa[i]]]=true; cnt++; } if(!out && cnt>k/2)return true; } } return false; } int main() { int m; while(scanf("%d",&m)!=EOF && m) { int top=0; for(int i=1; i<=m; i++) { scanf("%s",tmp); len[i]=strlen(tmp); for(int j=0; j<len[i]; j++) { index[top]=i; str[top++]=tmp[j]-'a'+1; } len[i]=len[i-1]+len[i]+1; index[top]=i; str[top++]=i+26; } if(m==1) { for(int i=0;i<len[1];i++) printf("%c",str[i]+'a'-1); puts("\n"); continue; } n=top; str[n-1]=0; suffix(256); getheight(); int l=0,r=n-1,ans=-1; while(l<=r) { int mid=(l+r)>>1; if(check(mid,m,0)) ans=mid,l=mid+1; else r=mid-1; } if(ans>0)check(ans,m,1); else printf("?\n"); puts(""); } return 0; }
POJ 3294 Life Forms (后缀数组),布布扣,bubuko.com
原文地址:http://blog.csdn.net/u010709592/article/details/36426935