POJ 3294 Life Forms(后缀数组)
来源:互联网 发布:武汉明源软件 编辑:程序博客网 时间:2024/06/06 01:32
题目链接:http://poj.org/problem?id=3294
题意:给定m个串,要求你求在在大于一半的串中出现串的最长长度,并输出该串,如果有多组同时输出(按照字典序)。
其实这个题目还是后缀数组的经典做法,枚举长度,最后的字典序输出其实没必要考虑,因为在后缀数组的处理过程中
本来就是按照后缀排好序的,所以求出来的结果一定是有序的,所以我们只要专注于程序的核心实现就好了
后缀数组处理多个字符串问题肯定是拼接,然后中间插入一个没有见过的字符,但是这里有个问题,如果单纯就用字符来
处理的话哪有那么多不同的字符呢,m最大为1000呢,所以在处理的时候转换成整形,这样就基本上无限了,接下来就是
二分枚举答案,按照height值排序分组,看看每个分组中出现在不同串中的个数,且height>=mid的大于m/2的就符合题目条件
找出来即可!
用belong数组还记录每个位置属于哪一个串,然后用is_visit标记这个串中是否出现过,为了防止不同分组中的出现冲突问题,
对于每个分组is_visit给一个不同的整形数来标记是否出现appear!
所以说这个题目只要掌握了后缀数组处理问题的基本方法写程序时细心一点基本上就是1A的节奏了!
#include <iostream>#include <stdio.h>#include <algorithm>#include <math.h>#include <string.h>using namespace std;#define MAX(a,b) (a>b?a:b)#define maxn 110000#define ws ws1int wa[maxn],wb[maxn],wv[maxn],ws[maxn];int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}void da(int *r,int *sa,int n,int m){int i,j,p,*x=wa,*y=wb,*t;for(i=0;i<m;i++) ws[i]=0;for(i=0;i<n;i++) ws[x[i]=r[i]]++;for(i=1;i<m;i++) ws[i]+=ws[i-1];for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;for(j=1,p=1;p<n;j*=2,m=p){for(p=0,i=n-j;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++) ws[i]=0;for(i=0;i<n;i++) ws[wv[i]]++;for(i=1;i<m;i++) ws[i]+=ws[i-1];for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;}int rank[maxn],height[maxn];void calheight(int *r,int *sa,int n){int i,j,k=0;for(i=1;i<=n;i++) rank[sa[i]]=i;//在计算height的时候顺便就把rank计算出来了,反正也要用for(i=0;i<n;height[rank[i++]]=k)for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);return;}char str[maxn];int rec[maxn];int sa[maxn],belong[maxn],n,num,m,pos,now,ans[1500],length;int is_visit[1500];int find_ans(int mid){ memset(is_visit,0,sizeof(is_visit)); int i,j,k,temp=1,appear=1; now=0; is_visit[belong[sa[1]]]=appear; for(i=2;i<=n;i++){ if(height[i]>=mid){ if(is_visit[belong[sa[i]]]!=appear) k=sa[i],temp++,is_visit[belong[sa[i]]]=appear; } else{ if(temp > m/2) ans[now++]=k,length=mid; temp=1; appear++; is_visit[belong[sa[i]]]=appear; } } if(now > 0){pos=now;return 1;} return 0;}int solve(){ int l=1,r=1001,mid,i,j,k; while(l<=r){ mid=(l+r)>>1; if(find_ans(mid)) l=mid+1; else r=mid-1; } if(pos==0){ printf("\?\n\n");return 0;} for(i=0;i<pos;i++){ for(j=0;j<length;j++) printf("%c",char((rec+ans[i])[j])); printf("\n"); } printf("\n"); return 0;}int main(){ int i,j,k,big; while(scanf("%d",&m),m){ big=129,n=0; for(i=1;i<=m;i++){ scanf("%s",str); if(i!=0) belong[n]=i,rec[n++]=big++; for(j=0;str[j];j++) belong[n]=i,rec[n++]=str[j]; } rec[n]=0; da(rec,sa,n+1,2000);//这里是n+1 因为看这个函数里面是 < n 的 calheight(rec,sa,n);//注意这里面是 n 了因为看函数里面是 <=n 的,所以这里要注意 pos=length=0; solve(); } return 0;}
- poj 3294 Life Forms(后缀数组+二分)
- poj 3294 Life Forms(后缀数组)
- poj 3294 Life Forms (后缀数组)
- POJ 3294 Life Forms(后缀数组)
- POJ 3294 Life Forms(后缀数组)
- POJ 3294 Life Forms (后缀数组)
- [后缀数组+二分] poj 3294 Life Forms
- POJ 3294 Life Forms 后缀数组
- 【后缀数组】【poj 3294】Life Forms
- poj 3294 Life Forms (后缀数组应用)
- POJ 3294 Life Forms (后缀数组)
- poj 3294 Life Forms (后缀数组)
- POJ 3294 Life Forms <后缀数组+二分>
- |poj 3294|后缀数组|二分|Life Forms
- 【*】POJ-3294(后缀数组)(Life Forms)
- POJ 3294 (UVA 11107) Life Forms 后缀数组
- poj 3294(Life Forms) 2分+ 后缀数组
- 【poj 3294】 Life Forms 后缀数组 *height分组
- jdbc connection c3p0详细配置
- C语言深度解剖读书笔记(1.关键字的秘密)
- 怎样使用google
- [SDK]新浪微博请求授权显示错误页面的解决方法(error:redirect_uri_mismatch)
- C语言深度解剖读书笔记(2.字符的技巧)
- POJ 3294 Life Forms(后缀数组)
- Windows API——OpenClipboard——剪切板
- C语言深度解剖读书笔记(3.预编译处理)
- <div>的display:none属性的继承
- SharePoint 2013的100个新功能之搜索(二)
- UVa 10370 - Above Average
- Android游戏开发&Android软件开发【教程三十二篇】
- git rebase后commit丢失
- RFS的web自动化验收测试——FAQ常见问题指引