POJ3294 Life Forms(二分+后缀数组)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3294 Life Forms(二分+后缀数组)相关的知识,希望对你有一定的参考价值。
给n个字符串,求最长的多于n/2个字符串的公共子串。
依然是二分判定+height分组。
- 把这n个字符串连接,中间用不同字符隔开,跑后缀数组计算出height;
- 二分要求的子串长度,判断是否满足:height分组,统计一个组不同的字符串个数是否大于n/2;
- 最后输出方案,根据二分得出的子串长度的结果,直接再遍历一遍height,因为这儿是有序的后缀所以找到一个就直接输出。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 111000 7 8 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; 9 int cmp(int *r,int a,int b,int l){ 10 return r[a]==r[b] && r[a+l]==r[b+l]; 11 } 12 int sa[MAXN],rank[MAXN],height[MAXN]; 13 void SA(int *r,int n,int m){ 14 int *x=wa,*y=wb; 15 16 for(int i=0; i<m; ++i) ws[i]=0; 17 for(int i=0; i<n; ++i) ++ws[x[i]=r[i]]; 18 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 19 for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; 20 21 int p=1; 22 for(int j=1; p<n; j<<=1,m=p){ 23 p=0; 24 for(int i=n-j; i<n; ++i) y[p++]=i; 25 for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; 26 for(int i=0; i<n; ++i) wv[i]=x[y[i]]; 27 for(int i=0; i<m; ++i) ws[i]=0; 28 for(int i=0; i<n; ++i) ++ws[wv[i]]; 29 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 30 for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i]; 31 swap(x,y); x[sa[0]]=0; p=1; 32 for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 33 } 34 35 for(int i=1; i<n; ++i) rank[sa[i]]=i; 36 int k=0; 37 for(int i=0; i<n-1; height[rank[i++]]=k){ 38 if(k) --k; 39 for(int j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k); 40 } 41 } 42 43 int n,m,r[MAXN],belong[MAXN]; 44 bool isok(int len){ 45 int cnt=0; 46 bool vis[111]={0}; 47 for(int i=2; i<=n; ++i){ 48 if(height[i]>=len){ 49 if(!vis[belong[sa[i]]]){ 50 vis[belong[sa[i]]]=1; 51 ++cnt; 52 } 53 if(!vis[belong[sa[i-1]]]){ 54 vis[belong[sa[i-1]]]=1; 55 ++cnt; 56 } 57 }else{ 58 if(cnt>(m>>1)) return 1; 59 memset(vis,0,sizeof(vis)); 60 cnt=0; 61 } 62 } 63 return 0; 64 } 65 void pnt(int len){ 66 int cnt=0,idx; 67 bool vis[111]={0}; 68 for(int i=2; i<=n; ++i){ 69 if(height[i]>=len){ 70 idx=sa[i]; 71 if(!vis[belong[sa[i]]]){ 72 vis[belong[sa[i]]]=1; 73 ++cnt; 74 } 75 if(!vis[belong[sa[i-1]]]){ 76 vis[belong[sa[i-1]]]=1; 77 ++cnt; 78 } 79 }else{ 80 if(cnt>(m>>1)){ 81 for(int j=0; j<len; ++j){ 82 putchar(r[idx+j]+‘a‘-1); 83 } 84 putchar(‘\n‘); 85 } 86 memset(vis,0,sizeof(vis)); 87 cnt=0; 88 } 89 } 90 } 91 int main(){ 92 char s[1111]; 93 while(~scanf("%d",&m) && m){ 94 n=0; 95 for(int i=0; i<m; ++i){ 96 scanf("%s",s); 97 for(int j=0; s[j]; ++j){ 98 belong[n]=i; 99 r[n++]=s[j]-‘a‘+1; 100 } 101 r[n++]=27+i; 102 } 103 r[--n]=0; 104 SA(r,n+1,127); 105 int l=0,r=1000; 106 while(l<r){ 107 int mid=l+r+1>>1; 108 if(isok(mid)) l=mid; 109 else r=mid-1; 110 } 111 if(l==0) puts("?"); 112 else pnt(l); 113 putchar(‘\n‘); 114 } 115 return 0; 116 }
以上是关于POJ3294 Life Forms(二分+后缀数组)的主要内容,如果未能解决你的问题,请参考以下文章
POJ 3294 Life Forms [最长公共子串加强版 后缀数组 && 二分]