[后缀数组+二分] poj 3294 Life Forms
2014-08-29 16:53
197 查看
题意:给你n个字符串,求出现次数超过一半的最长子串,如果多个按字典序输出,没有则输出“?”。
思路:首先将所有字符串连成一个长串,中间用一个互不相同的符号分隔。然后做后缀数组,然后同样二分求出最长的长度。
然后在通过最长长度枚举height,成立的串就输出,因为height实质就是枚举sa,sa是排好序的所以按顺序枚举就是字典序了。
思路:首先将所有字符串连成一个长串,中间用一个互不相同的符号分隔。然后做后缀数组,然后同样二分求出最长的长度。
然后在通过最长长度枚举height,成立的串就输出,因为height实质就是枚举sa,sa是排好序的所以按顺序枚举就是字典序了。
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"stack" #include"algorithm" #include"iostream" #include"map" using namespace std; #define N 103000 int wa ,wb ,wv ,wws ; int sa ,ra ,v ,height ,mark ; char fuck ; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int n,int m) { int i,j,p,*x=wa,*y=wb; for(i=0; i<m; i++) wws[i]=0; for(i=0; i<n; i++) wws[x[i]=v[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[x[i]]]=i; for(j=1,p=1; p<n; j*=2,m=p) { for(i=n-j,p=0; i<n; i++) y[p++]=i; for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0; i<n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) wws[i]=0; for(i=0; i<n; i++) wws[wv[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[wv[i]]]=y[i]; for(swap(x,y),p=1,i=1,x[sa[0]]=0; i<n; i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } return ; } void gethei(int n) { int i,j,k=0; for(i=1; i<=n; i++) ra[sa[i]]=i; for(i=0; i<n; i++) { if(k) k--; j=sa[ra[i]-1]; while(v[i+k]==v[j+k]) k++; height[ra[i]]=k; } return ; } int ok(int x,int n,int k) { int i; int used[102],sum=0; memset(used,0,sizeof(used)); for(i=1; i<=n; i++) { if(height[i]>=x) { if((mark[sa[i]]!=mark[sa[i-1]])&&(!used[mark[sa[i]]]||!used[mark[sa[i-1]]])) //判断是不是同一个串,并且其中一个没标记过。 { if(!used[mark[sa[i]]]) { sum++; used[mark[sa[i]]]=1; } if(!used[mark[sa[i-1]]]) { sum++; used[mark[sa[i-1]]]=1; } if(sum>k/2) return 1; } } else { memset(used,0,sizeof(used)); //注意每次都清零。 sum=0; } } return 0; } int main() { int n,cas=1; while(scanf("%d",&n),n) { if(cas!=1) puts(""); int cnt=0,i,j; for(i=1; i<=n; i++) { scanf("%s",fuck); for(j=0; fuck[j]; j++) { mark[cnt]=i; //标记当前的下标是属于哪个串的 v[cnt++]=fuck[j]-'a'+2; } v[cnt++]=30+i; //分隔每个字符串 } v[cnt]=0; da(cnt+1,200); gethei(cnt); int l=1,r=cnt; int ans=0; while(l<=r) //二分求长度 { int mid=(l+r)/2; if(ok(mid,cnt,n)) { ans=mid; l=mid+1; } else r=mid-1; } if(ans==0) { puts("?"); continue; } int sum=0,f=0; //f用来标记当前段是否输出过 int used[102]; memset(used,0,sizeof(used)); for(i=1; i<=cnt; i++) //枚举输出 { if(height[i]>=ans) { if((mark[sa[i]]!=mark[sa[i-1]])&&(!used[mark[sa[i]]]||!used[mark[sa[i-1]]])) { if(!used[mark[sa[i]]]) { sum++; used[mark[sa[i]]]=1; } if(!used[mark[sa[i-1]]]) { sum++; used[mark[sa[i-1]]]=1; } if(sum>n/2&&!f) { for(j=0; j<ans; j++) printf("%c",v[sa[i-1]+j]+'a'-2); puts(""); f=1; } } } else { memset(used,0,sizeof(used)); sum=0; f=0; } } cas++; } return 0; }
相关文章推荐
- POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串
- poj 3294 Life Forms(后缀数组+二分)
- poj_3294 Life Forms(后缀数组+二分)
- POJ3294---Life Forms(后缀数组,二分+给后缀分组)
- POJ 3294 Life Forms(后缀数组+二分)
- POJ 3294 后缀数组+二分
- Poj 3294 Life Forms(后缀数组+二分答案)
- POJ 3294 Life Forms 二分 + 哈希
- Poj 3294 Life Forms (后缀数组 + 二分 + Hash)
- POJ 3294 后缀数组+二分
- POJ 3294 Life Forms(后缀数组+二分答案)
- POJ 3294 Life Forms(后缀数组)
- poj 3294 求多于k个字符串的最长公共子串的个数-------后缀数组+二分答案
- poj 3294(Life Forms) 2分+ 后缀数组
- POJ 3450 3080 后缀数组+二分
- poj 3294 Life Forms
- POJ 3261 Milk Patterns 后缀数组+二分
- poj 3294 Life Forms(后缀数组)
- POJ-3294-Life Forms
- UVA 11107(Life Forms-后缀数组+二分)