poj3294 Life Forms(后缀数组)
2015-11-29 11:06
489 查看
【题目链接】
http://poj.org/problem?id=3294
【题意】
多个字符串求出现超过R次的最长公共子串。
【思路】
二分+划分height,判定一个组中是否包含不小于R个不同字符串的后缀。
需要注意的有:
1) c[]尽量开大,字符范围为“偏移”之后的范围。
2) 用kase作为标记节省了每次开始新段需要清零的时间。
3) 因为height是sa[i]与sa[i-1]的关系,所以无论是在can的开始还是在新段开始都需要初始为一个串的情况。
【代码】
http://poj.org/problem?id=3294
【题意】
多个字符串求出现超过R次的最长公共子串。
【思路】
二分+划分height,判定一个组中是否包含不小于R个不同字符串的后缀。
需要注意的有:
1) c[]尽量开大,字符范围为“偏移”之后的范围。
2) 用kase作为标记节省了每次开始新段需要清零的时间。
3) 因为height是sa[i]与sa[i-1]的关系,所以无论是在can的开始还是在新段开始都需要初始为一个串的情况。
【代码】
#include<cstdio> #include<cstring> #include<vector> #include<iostream> #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; const int maxn = 200000+10; int s[maxn]; int sa[maxn],c[maxn],t[maxn],t2[maxn]; void build_sa(int m,int n) { int i,*x=t,*y=t2; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[i]=s[i]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(i=n-k;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[y[i]]]++; for(i=0;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; if(p>=n) break; m=p; } } int rank[maxn],height[maxn]; void getHeight(int n) { int i,j,k=0; for(i=0;i<=n;i++) rank[sa[i]]=i; for(i=0;i<n;i++) { if(k) k--; j=sa[rank[i]-1]; while(s[j+k]==s[i+k]) k++; height[rank[i]]=k; } } int T; char a[maxn]; int f[200],kase; vector<int> st; int can(int limit,int n,int len) { int cnt=1,ok=0; st.clear(); f[sa[1]/len]=kase; for(int i=2;i<=n;i++) { if(height[i]<limit) { cnt=1; f[sa[i]/len]=++kase; //检查每一个组中 } else { if(f[sa[i]/len]!=kase) { f[sa[i]/len]=kase; if(cnt>=0) cnt++; if(cnt>T/2) { ok=1; st.push_back(sa[i]); cnt=-1; } } } } return ok; } void init() { kase=1; memset(sa,0,sizeof(sa)); memset(f,0,sizeof(f)); } int main() { //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); while(scanf("%d",&T)==1 && T) { init(); int len,n=0; for(int i=0;i<T;i++) { scanf("%s",&a); len=strlen(a); for(int j=0;j<len;j++) s[n++]=a[j]+100; s[n++]=i+1; } n--; s =0; build_sa(250,n+1); getHeight(n); int L=0,R=len+1; while(L<R) { int M=L+(R-L+1)/2; if(can(M,n,len+1)) L=M; else R=M-1; } can(L,n,len+1); //再调用一次求出st if(L==0) printf("?\n"); else { for(int i=0;i<st.size();i++) { for(int j=st[i];(j-st[i]+1)<=L;j++) printf("%c",s[j]-100); putchar('\n'); } } putchar('\n'); } return 0; }
相关文章推荐
- jquery+php实现滚动的数字特效
- MVC Ajax Helper或Jquery异步加载部分视图
- jQuery的i18n插件的一个限制
- HTML5绘制实心的文本
- web 前端页面性能优化总结
- Javascript闭包实例详解
- jQuery实现图片上传和裁剪插件Croppie
- [Nodejs入门]第四篇,用nodejs实现一个爬虫的功能
- javascript高级编程之函数表达式 递归和闭包函数
- javascript实现拖动元素交换位置
- javascript实现网页中涉及的简易运动(改变宽高、透明度、位置)
- 通用javascript代码判断版本号是否在版本范围之间
- 前端css编码规范
- jQuery如何使用自动触发事件trigger
- js性能优化技巧
- 使用JavaScript编程分析多级嵌套JSON文档数据
- javascript实现C语言经典程序题
- 详解js闭包
- JavaScript学习小结(7)之JS RegExp
- 整理Javascript基础入门学习笔记