UVA-11107 Life Forms(后缀数组)
题目大意:给出n个字符串,找出所有最长的在超过一半的字符串中出现的子串。
题目分析:将所有的字符串连成一个,二分枚举长度,每次用O(n)的时间复杂度判断。连接字符串的时候中间添一个没有出现过的字符。
代码如下:
# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
# define mid (l+(r-l)/2)
# define LL long long const int N=100000; char s[N+105];
int SA[N+105],tSA[N+105];
int rk[N+105],cnt[N+105];
int height[N+105];
int flag[N+105];
bool vis[105]; int idx(char c)
{
return c-'a';
} bool same(int i,int j,int k,int n)
{
if(tSA[SA[i]]!=tSA[SA[j]]) return false;
if(SA[i]+k>=n&&SA[j]+k>=n) return true;
if(SA[i]+k<n&&SA[j]+k>=n) return false;
if(SA[i]+k>=n&&SA[j]+k<n) return false;
return tSA[SA[i]+k]==tSA[SA[j]+k];
} void buildSA()
{
int m=27;
int n=strlen(s);
for(int i=0;i<m;++i) cnt[i]=0;
for(int i=0;i<n;++i) ++cnt[rk[i]=idx(s[i])];
for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;--i) SA[--cnt[rk[i]]]=i; for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k;i<n;++i) tSA[p++]=i;
for(int i=0;i<n;++i) if(SA[i]>=k) tSA[p++]=SA[i]-k; for(int i=0;i<m;++i) cnt[i]=0;
for(int i=0;i<n;++i) ++cnt[rk[tSA[i]]];
for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;--i) SA[--cnt[rk[tSA[i]]]]=tSA[i]; swap(rk,tSA);
rk[SA[0]]=0;
p=1;
for(int i=1;i<n;++i){
if(same(i,i-1,k,n)) rk[SA[i]]=p-1;
else rk[SA[i]]=p++;
}
if(p>=n) break;
m=p;
}
} void getHeight()
{
int n=strlen(s);
for(int i=0;i<n;++i) rk[SA[i]]=i;
int k=0;
for(int i=0;i<n;++i){
if(rk[i]==0)
height[rk[i]]=k=0;
else{
if(k) --k;
int j=SA[rk[i]-1];
while(s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
}
} bool judge(int x,int n)
{
memset(vis,false,sizeof(vis));
vis[flag[SA[0]]]=true;
int k=1;
int len=strlen(s);
for(int i=1;i<len;++i){
if(k>n) return true;
if(flag[SA[i]]==-1)
break;
if(height[i]<x){
k=0;
memset(vis,false,sizeof(vis));
}
if(!vis[flag[SA[i]]]){
vis[flag[SA[i]]]=true;
++k;
}
}
return k>n;
} int f(int l,int r,int n)
{
++r;
while(l<r){
if(judge(mid,n)) l=mid+1;
else r=mid;
}
return r-1;
} bool ok(int i,int j)
{
return flag[i]==flag[j];
} void print(int p,int n)
{
int len=strlen(s);
memset(vis,false,sizeof(vis));
int k=1;
vis[flag[SA[0]]]=true;
for(int i=1;i<len;++i){
if(flag[SA[i]]==-1||height[i]<p){
if(k>n&&ok(SA[i-1],SA[i-1]+p-1)){
for(int j=SA[i-1];j<SA[i-1]+p;++j) printf("%c",s[j]);
puts("");
}
if(flag[SA[i]]==-1) break;
k=0;
memset(vis,false,sizeof(vis));
}
if(!vis[flag[SA[i]]]){
++k;
vis[flag[SA[i]]]=true;
}
}
} int main()
{
int n;
bool yy=false;
while(scanf("%d",&n)&&n)
{
if(yy) puts("");
yy=true;
if(n==1){
scanf("%s",s);
printf("%s\n",s);
}else{
memset(flag,-1,sizeof(flag));
s[0]=0;
int high=0;
for(int i=0;i<n;++i){
int m=strlen(s);
scanf("%s",s+m);
int nm=strlen(s);
for(int j=m;j<nm;++j) flag[j]=i;
s[nm]='z'+1;
s[nm+1]=0;
high=max(nm-m,high);
}
buildSA();
getHeight();
int len=f(0,high,n>>1);
if(len<=0) printf("?\n");
else print(len,n>>1);
}
}
return 0;
}
UVA-11107 Life Forms(后缀数组)的更多相关文章
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- 后缀数组LCP + 二分 - UVa 11107 Life Forms
Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...
- UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)
题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...
- UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
- UVA 12206 - Stammering Aliens(后缀数组)
UVA 12206 - Stammering Aliens 题目链接 题意:给定一个序列,求出出现次数大于m,长度最长的子串的最大下标 思路:后缀数组.搞出height数组后,利用二分去查找就可以 这 ...
- UVA11107 Life Forms --- 后缀数组
UVA11107 Life Forms 题目描述: 求出出现在一半以上的字符串内的最长字符串. 数据范围: \(\sum len(string) <= 10^{5}\) 非常坑的题目. 思路非常 ...
- UVA 11107(Life Forms-后缀数组+二分)
Problem C: Life Forms You may have wondered why most extraterrestrial life forms resemble humans, di ...
- POJ3294 Life Forms —— 后缀数组 最长公共子串
题目链接:https://vjudge.net/problem/POJ-3294 Life Forms Time Limit: 5000MS Memory Limit: 65536K Total ...
- UVA 10526 - Intellectual Property (后缀数组)
UVA 10526 - Intellectual Property 题目链接 题意:给定两个问题,要求找出第二个文本抄袭第一个文本的全部位置和长度,输出前k个,按长度从大到小先排.长度一样的按位置从小 ...
- Poj 3294 Life Forms (后缀数组 + 二分 + Hash)
题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...
随机推荐
- 爬虫:获取多次跳转后的页面url
<?php $url = "xxxx"; $xx = get_headers($url,true); var_dump($xx); ?> Nbimer主页 剖面加阴影应 ...
- CSS 3 动画2D
动画分为两种,1,逐帧动画 组成动画的每一个画面就是一帧 2,关键帧动画,确定关键帧电脑会自动过度 动画中如果遇到不兼容的问题也是要加前缀 @-webkit-keyframes规则 @-webk ...
- 利用react来制作评论框
学习地址:https://my.oschina.net/leogao0816/blog/379488
- Chinese culture
文房四宝 笔墨纸砚是中国古代文人书房中必备的宝贝,被称为“文房四宝”.用笔墨书写绘画在 中国可追溯到五千年前.秦(前221---前206)时已用不同硬度的毛和竹管制笔:汉代(前206—公元220) ...
- 解决Jenkins打不开浏览器问题
参考:http://blog.csdn.net/achang21/article/details/45096003 1.控制面板禁用掉jenkins服务 2.java -jar jenkins.war ...
- 51nod 1134 最长递增子序列
题目链接:51nod 1134 最长递增子序列 #include<cstdio> #include<cstring> #include<algorithm> usi ...
- 【堆栈应用一】一个数divided=几个最小质因数的乘积(时间复杂度On)
此算法由LQD提供
- 读javascript高级程序设计08-引用类型之Global、Math、String
一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encod ...
- JSON认识
阅读目录 JSON的两种结构 认识JSON字符串 在JS中如何使用JSON 在.NET中如何使用JSON 总结 JSON的全称是”JavaScript Object Notation”,意思是Java ...
- iOS开发UI篇—UIWindow简单介绍
iOS开发UI篇—UIWindow简单介绍 一.简单介绍 UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow iOS程序启动完毕后,创建的第一个视图控件就是UIWi ...