poj 3294 Life Forms
后缀数组的题目,把后缀连接起来,这个还是先二分答案,然后选取一段连续的height值,判断这些height代表的后缀有没有覆盖一半以上的字符串。
得出答案的长度之后还要在枚举连续的heigh,判断有没有答案,有的话标记其中一个。
最后再按照sa输出答案。这样就可以保证字典序。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=1e5+10000; int r[maxn]; char a[1111]; int *rank,height[maxn],sa[maxn]; int wx[maxn],wy[maxn],cnt[maxn]; int n,m; inline bool 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 n,int m) { r[n+1]=0; int i,l,p,*x=wx,*y=wy,*t; memset(cnt,0,sizeof(int)*(m+1)); for(int i=1;i<=n;i++) cnt[x[i]=r[i]]++; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) sa[cnt[x[i]]--]=i; for(l=1,p=1;p<n;l<<=1,m=p) { for(p=1,i=n-l+1;i<=n;i++) y[p++]=i; for(i=1;i<=n;i++) if(sa[i]>l) y[p++]=sa[i]-l; memset(cnt,0,sizeof(int)*(m+1)); for(i=1;i<=n;i++) cnt[x[i]]++; for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(i=n;i>=1;i--) sa[cnt[x[y[i]]]--]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[1]]=1,i=2;i<=n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],l)?p:++p; } rank=x; int j,k=0; for(i=1;i<=n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); return; } bool fla[1111]; int c[maxn]; bool ans[maxn]; bool chk(int ret) { for(int i=2;i<=n;i++) if(height[i]>=ret) { int j=i+1; while(j<=n&&height[j]>=ret) j++; j--; memset(fla,0,sizeof(fla)); for(int k=i-1;k<=j;k++) fla[c[sa[k]]]=1; int cnt=0; for(int k=1;k<=m;k++) cnt+=fla[k]; if(cnt>m/2) return true; i=j; } return false; } int main() { // freopen("in.txt","r",stdin); int ret; int tt=0; while(scanf("%d",&m),m) { if(tt++) printf("\n"); n=0; for(int i=1;i<=m;i++) { scanf("%s",a+1); ret=strlen(a+1); for(int j=1;j<=ret;j++) r[n+j]=a[j]; for(int j=n+1;j<=n+ret;j++) c[j]=i; n+=ret; r[++n]=570+i; } da(r,n,680); int st=0,ed=1111,mid; while(st<ed) { mid=st+ed+1>>1; if(chk(mid)) st=mid; else ed=mid-1; } if(m==1) { for(int i=1;i<n;i++) printf("%c",r[i]); printf("\n"); } else if(st==0) printf("?\n"); else { memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++) if(height[i]>=st) { int j=i+1; while(height[j]>=st) j++; j--; memset(fla,0,sizeof(fla)); for(int k=i-1;k<=j;k++) fla[c[sa[k]]]=1; int cnt=0; for(int k=1;k<=m;k++) cnt+=fla[k]; if(cnt>m/2) { ans[sa[i-1]]=1; } i=j; } for(int i=1;i<=n;i++) if(ans[sa[i]]) { for(int j=1;j<=st;j++) printf("%c",r[j+sa[i]-1]); printf("\n"); } } } return 0; }