poj3294 Life Forms(后缀数组+并查集)
http://poj.org/problem?id=3294
题意:
n个字符串,求至少出现在n/2个字符串中的最长公共子串,按字典序输出所有解
在下面这个题的接触上输出所有的解
https://www.cnblogs.com/TheRoadToTheGold/p/15142861.html
确定好最长长度之后,把所有满足要求的起点记录一下即可
注意去重
因为忽略了标准ASCII码<=127,在添加特殊字符连接的时候出现了问题,RE了一个小时,555~
#include<cmath> #include<vector> #include<cstdio> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 106009 char ch[N]; int m,n,k,a[N],v[N],p,q,sa[2][N],rk[2][N],h[N]; int t,fa[N]; vector<int>hv[N]; int may[N],tot; bitset<100>bl[N]; void mul(int *sa,int *rk,int *SA,int *RK) { for(int i=1;i<=n;i++) v[rk[sa[i]]]=i; for(int i=n;i;i--) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i; for(int i=1;i<=n;i++) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); } void presa() { p=0; q=1; for(int i=1;i<=26+t;++i) v[i]=0; for(int i=1;i<=n;i++) v[a[i]]++; for(int i=1;i<=26+t;i++) v[i]+=v[i-1]; for(int i=1;i<=n;i++) sa[p][v[a[i]]--]=i; for(int i=1;i<=n;i++) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]); for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); for(int i=1,k=0;i<=n;i++) { int j=sa[p][rk[p][i]-1]; while(a[i+k]==a[j+k]) k++; h[rk[p][i]]=k;if(k) k--; } } int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); } void unionn(int x,int y) { bl[sa[p][x]]|=bl[sa[p][y]]; fa[y]=x; } void solve() { for(int i=0;i<n;++i) hv[i].clear(); for(int i=2;i<=n;++i) hv[h[i]].push_back(i); for(int i=1;i<=n;++i) fa[i]=i; bool tag=true; int m,f1,f2,le; tot=0; for(int i=n-1;i && tag;--i) { m=hv[i].size(); for(int j=0;j<m;++j) { f1=find(hv[i][j]); f2=find(hv[i][j]-1); if(f1!=f2) { unionn(f2,f1); if(tot) { bool rep=true; for(int ll=0;ll<i && rep;++ll) if(ch[sa[p][may[tot]]+ll]!=ch[sa[p][f2]+ll]) rep=false; if(rep) continue; } if(bl[sa[p][f2]].count()>=(t>>1)+1) { tag=false; le=i; may[++tot]=f2; } } } } for(int i=1;i<=tot;++i) { for(int j=0;j<le;++j) printf("%c",ch[sa[p][may[i]]+j]); printf("\n"); } if(!tot) printf("?\n"); printf("\n"); } int main() { int last; while(1) { scanf("%d",&t); if(!t) return 0; last=n=0; for(int i=1;i<=t;++i) { scanf("%s",ch+n+1); n=strlen(ch+1); for(int j=last+1;j<=n;++j) { bl[j].reset(); bl[j].set(i-1); a[j]=ch[j]-'a'+1; } a[++n]=26+i; ch[n]=' '; last=n; } if(t==1) { ch[n]='\0'; printf("%s\n\n",ch+1); continue; } presa(); solve(); } }