POJ - 3294 Life Forms
传送门:POJ - 3294 (类似题目POJ - 3450)
题意:给你n个字符串,求在不小于k/2个字符串中出现过的最长子串。
题解:首先将n个字符串连起来,中间用不一样且没出现过的字符连起来(这个地方让我wa了好几发!!),然后二分字串的长度,将后缀分成若干组,判断每组的后缀是否在不小于k个的原串中出现过,数组sum记录每个最长字符串在原串中出现的位置sa[i]。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<iostream> 5 #include<cmath> 6 #include<cstring> 7 using namespace std; 8 9 const int maxn = 1000100; 10 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn]; 11 int rnk[maxn],height[maxn],sum[maxn]; 12 char s[maxn]; 13 int r[maxn],n,pos=0,len[110],vis[110],ans=0,L,be[maxn]; 14 15 //sa:字典序中排第i位的起始位置在str中第sa[i] sa[1~n]为有效值 16 17 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值 18 19 //height:字典序排i和i-1的后缀的最长公共前缀 height[2~n]为有效值,第二个到最后一个 20 21 int cmp(int *r,int a,int b,int k) 22 { 23 return r[a]==r[b]&&r[a+k]==r[b+k]; 24 } 25 26 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长 27 { 28 int i,j,p,*x=wa,*y=wb,*t; 29 for(i=0; i<m; i++) wsf[i]=0; 30 for(i=0; i<=n; i++) wsf[x[i]=r[i]]++; 31 for(i=1; i<m; i++) wsf[i]+=wsf[i-1]; 32 for(i=n; i>=0; i--) sa[--wsf[x[i]]]=i; 33 p=1; 34 j=1; 35 for(; p<=n; j*=2,m=p){ 36 for(p=0,i=n+1-j; i<=n; i++) y[p++]=i; 37 for(i=0; i<=n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; 38 for(i=0; i<=n; i++) wv[i]=x[y[i]]; 39 for(i=0; i<m; i++) wsf[i]=0; 40 for(i=0; i<=n; i++) wsf[wv[i]]++; 41 for(i=1; i<m; i++) wsf[i]+=wsf[i-1]; 42 for(i=n; i>=0; i--) sa[--wsf[wv[i]]]=y[i]; 43 swap(x,y); 44 x[sa[0]]=0; 45 for(p=1,i=1; i<=n; i++) 46 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++; 47 } 48 } 49 50 void getheight(int *r,int n)//n为添加0后的总长 51 { 52 int i,j,k=0; 53 for(i=1; i<=n; i++) rnk[sa[i]]=i; 54 for(i=0; i<n; i++){ 55 if(k) 56 k--; 57 else 58 k=0; 59 j=sa[rnk[i]-1]; 60 while(r[i+k]==r[j+k]) 61 k++; 62 height[rnk[i]]=k; 63 } 64 } 65 66 bool check(int k) 67 { 68 int cnt=0,p=0; 69 memset(vis,0,sizeof(vis)); 70 for(int i=1;i<=L;i++){ 71 if(height[i]>=k){ 72 if(!vis[be[sa[i]]]) cnt++; 73 vis[be[sa[i]]]=1; 74 if(!vis[be[sa[i-1]]]) cnt++; 75 vis[be[sa[i-1]]]=1; 76 } 77 else{ 78 if(cnt>n/2) sum[p++]=sa[i-1]; 79 cnt=0; 80 memset(vis,0,sizeof(vis)); 81 } 82 } 83 if(cnt>n/2) sum[p++]=sa[L]; 84 cnt=0; 85 if(p) ans=p; 86 if(p) return 1; 87 return 0; 88 } 89 90 int main() 91 { 92 ios::sync_with_stdio(false); 93 cin.tie(0); 94 cout.tie(0); 95 int t=0; 96 while(cin>>n&&n){ 97 L=0; 98 for(int i=1;i<=n;i++){ 99 cin>>s+L; 100 int p=strlen(s+L); 101 for(int j=0;j<p;j++){ 102 r[j+L]=s[j+L]-'A'+1; 103 be[j+L]=i; 104 } 105 L+=p; 106 len[i]=L; 107 if(i!=n){ 108 r[L]=100+i; 109 be[L]=i; 110 L++; 111 } 112 } 113 r[L]=0; 114 getsa(r,sa,L,300); 115 getheight(r,L); 116 int l=1,r=L; 117 ans=0; 118 while(l<=r){ 119 int mid=l+r>>1; 120 if(check(mid)){ 121 l=mid+1; 122 } 123 else r=mid-1; 124 } 125 if(t) cout<<endl; 126 t=1; 127 if(l==1) cout<<"?"<<endl; 128 for(int i=0;i<ans;i++){ 129 for(int j=sum[i];j<sum[i]+l-1;j++){ 130 cout<<s[j]; 131 } 132 cout<<endl; 133 } 134 } 135 return 0; 136 }