poj3294 Life Forms
【题意】
求出现次数超过一半的最长子串
【分析】
把所有的串连在一起,中间放上间隔符,然后求height之后
二分答案转换为判定问题,每次按height分组,看一组中是否出现了超过一半次数即可
【代码】
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; int n,len[105]; char s[1005]; const int maxn=100*1005; int a[maxn],siz; int cnt[maxn],fz[maxn],oldrk[maxn],sa[maxn],id[maxn],rk[maxn],h[maxn],pos[maxn]; bool cmp(int x,int y,int w) { return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w]; } void calcsa() { int m=350; for(int i=0;i<=m;i++) cnt[i]=0; for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i; int i,j,p=m; for(int w=1;;w<<=1,m=p) { for(p=0,i=n;i>n-w;i--) id[++p]=i; for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w; for(i=0;i<=m;i++) cnt[i]=0; for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++; for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i]; for(i=1;i<=n;i++) oldrk[i]=rk[i]; for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p; if(p==n) { for(i=1;i<=n;i++) sa[rk[i]]=i; break; } } } void calch() { int i,k=0; for(i=1;i<=n;i++) { if(k) k--; while(a[i+k]==a[sa[rk[i]-1]+k]) k++; h[rk[i]]=k; } } bool check(int x) { int cntt=0,tot=0,vis[104]; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { if(h[i]>=x) { for(int j=1;j<=siz;j++) { if(sa[i]>len[j-1] && sa[i]<=len[j]) cntt+=vis[j]?0:1,vis[j]=1; if(sa[i-1]>len[j-1] && sa[i-1]<=len[j]) cntt+=vis[j]?0:1,vis[j]=1; } } else { if(cntt>siz/2) pos[++tot]=sa[i-1]; cntt=0; memset(vis,0,sizeof(vis)); } } if(cntt>siz/2) pos[++tot]=sa[n]; if(tot) { pos[0]=tot; return 1; } return 0; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int round=0; while(scanf("%d",&n)!=EOF && n) { for(int i=1;i<=n;i++) { scanf("%s",s); int l=strlen(s); len[i]=len[i-1]+1; for(int j=0;j<l;j++) a[len[i]+j]=s[j]-'a'+1; len[i]+=l-1; if(i!=n) len[i]++,a[len[i]]=26+i; } siz=n; n=len[n]; calcsa(); calch(); int l=0,r=n; while(l<=r) { int mid=l+r>>1; if(check(mid)) l=mid+1; else r=mid-1; } if(round) printf("\n"); if(l==1) { printf("?\n"); continue; } for(int i=1;i<=pos[0];i++) { for(int j=pos[i];j<pos[i]+l-1;j++) printf("%c",a[j]+'a'-1); printf("\n"); } round++; } return 0; }

浙公网安备 33010602011771号