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 ...
随机推荐
- 《BI那点儿事》数据仓库建模:星型模式、雪片模式
数据仓库建模 — 星型模式Example of Star Schema 数据仓库建模 — 雪片模式Example of Snowflake Schema 节省存储空间 一定程度上的范式 星形 vs.雪 ...
- js中对radio和checkbox是否选中的判断
一.js判断checkbox 例如:<div class="checkbox" style="width: 150px;"> <label&g ...
- SpringMVC报错The request sent by the client was syntactically incorrect ()
springmvc数据绑定出的错 在数据绑定的时候一定要主意Controller方法中的参数名和jsp页面里的参数名字是否一致或者按照绑定的规范来写, 如果不一致,可能回报如下错误: The requ ...
- linux配置ssh互信
公钥认证的基本思想: 对信息的加密和解密采用不同的key,这对key分别称作private key和public key,其中,public key存放在欲登录的服务器上,而private key为特 ...
- 浅谈AJAX的基本原理和原生AJAX的基础用法
一.什么是AJAX? AJAX,即"Asynchronous Javascript And XML",翻译为异步的JavaScript和XML,是一种创建交互式网页应用的网页开发技 ...
- thinkphp分页搜索条件带中文参数
/** * 中文处理 * @param type $str * @return str * $author lxh */ function url2word($str){ $sub=strpos($s ...
- linux笔记:shell基础-bash变量
shell变量设置规则: 变量的分类: 环境变量的设置: 系统常见环境变量: 位置参数变量(用来接收脚本的参数): 预定义变量: 接收键盘输入(将键盘输入的值赋值给变量名): 用declare声明变量 ...
- jquery打字机效果
html代码 <div id="box"> <div id="content"> <div id="code" ...
- Linux cat命令的使用
cat命令主要用来查看文件内容,创建文件,文件合并,追加文件内容等功能. A:查看文件内容主要用法: 1.cat f1.txt,查看f1.txt文件的内容. 2.cat -n f1.txt,查看f ...
- div仿textarea
CSS代码: .test_box { width: 400px; min-height: 120px; max-height: 300px; _height: 120px; margin-left: ...