UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)

题解:
题意:
输入n个DNA序列,你的任务是求出一个长度最大的字符串,使得它在超过一半的DNA序列中出现。如果有多解,按照字典序从小到大输入所有解。
把n个DNA序列拼在一起,中间用没有出现过的字符分割。然后求出height数组。
二分满足要求的字符串长度L,然后判断是否可行。
判断可行:
分组方法,如果某一组(段)有超过n/2的DNA串(是对应的输入的DNA串要有n/2个),则可行。
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=*+;
const int maxm=*;
int idx[maxm],n;
struct SuffixArray{
int s[maxm];
int sa[maxm],height[maxm],rank[maxm],n;
int t[maxm*],t2[maxm*];
long long cnt[maxm];
void clear(){n=;}
void build_sa(int m)
{
int i,*x=t,*y=t2;
for(i=;i<m;i++) cnt[i]=;
for(i=;i<n;i++) cnt[x[i]=s[i]]++;
for(i=;i<m;i++) cnt[i]+=cnt[i-];
for(i=n-;i>=;i--) sa[--cnt[x[i]]]=i;
for(int k=,p=;k<n;k <<=)
{
p=;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=;i<m;i++) cnt[i]=;
for(i=;i<n;i++) cnt[x[y[i]]]++;
for(i=;i<m;i++) cnt[i]+=cnt[i-];
for(i=n-;i>=;i--) sa[--cnt[x[y[i]]]]=y[i];
swap(x,y);
p=;x[sa[]]=;
for(i=;i<n;i++)
{
if(y[sa[i-]]==y[sa[i]]&&y[sa[i-]+k]==y[sa[i]+k]) x[sa[i]]=p-;
else x[sa[i]]=p++;
}
if(p>=n) break;
m=p;
}
}
void build_height()
{
int k=;
for(int i=;i<n;i++) rank[sa[i]]=i;
for(int i=;i<n;i++)
{
if(k) k--;
if(!rank[i]) continue;
int j=sa[rank[i]-];
while(s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
}
} SA; inline void add(int ch,int id)
{
idx[SA.n]=id;
SA.s[SA.n++]=ch;////
} int flag[maxn];
inline int check(int ans)
{
int check_clock=;
memset(flag,,sizeof(flag));
for(int i=;i<SA.n;i++)
{
if(SA.height[i]>=ans)
{
flag[idx[SA.sa[i]]]=check_clock;
flag[idx[SA.sa[i-]]]=check_clock;
}
else
{
int cnt=;
for(int j=;j<n;j++) if(flag[j]==check_clock) cnt++;
if(cnt>n/) return true;
flag[idx[SA.sa[i]]]=++check_clock;
}
}
return false;
} inline void print_ans(int l,int r)
{
for(int i=l;i<=r;i++) printf("%c",SA.s[i]+'a'-);
printf("\n");
} inline void print(int ans)
{
int check_clock=;
memset(flag,,sizeof(flag));
for(int i=;i<SA.n;i++)
{
if(SA.height[i]>=ans)
{
flag[idx[SA.sa[i]]]=check_clock;
flag[idx[SA.sa[i-]]]=check_clock;
}
else
{
int cnt=;
for(int j=;j<n;j++) if(flag[j]==check_clock) cnt++;
if(cnt>n/) print_ans(SA.sa[i-],SA.sa[i-]+ans-);
flag[idx[SA.sa[i]]]=++check_clock;
}
}
}
char s[+];
int kase=;
int main()
{
int maxlen;
while(scanf("%d",&n)==&&n)
{
if(kase++) printf("\n");
SA.clear();
maxlen=;
for(int i=;i<n;i++)
{
scanf("%s",s);
int l=strlen(s);
maxlen=max(maxlen,l);
for(int j=;j<l;j++) add(s[j]-'a'+,i);
add(+i,n);
}
if(n==) {printf("%s\n",s);continue;}
SA.build_sa(+n);
SA.build_height();
int l=,r=maxlen,ans=;
while(l<=r)
{
int mid=((l+r)>>);
if(check(mid)) ans=mid,l=mid+;
else r=mid-;
}
if(ans) print(ans);
else printf("?\n");
}
return ;
}
UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)的更多相关文章
- POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串
Life Forms Time Limit: 500 ...
- POJ 3294 Life Forms(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...
- poj 3294 Life Forms - 后缀数组 - 二分答案
题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...
- ural1297 求最长回文子串 | 后缀数组
#include<cstdio> #include<algorithm> #include<cstring> #define N 20005 using names ...
- POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串
Life Forms Description You may have wondered why most extraterrestrial life forms resemble humans, ...
- uva 11107 Life Forms
题意:给你N个串,求一个串在大于等于N/2的模板串中连续出现.如果有多解按字典序最小输出. 白书模板题.二分答案+合并模板串成一个新串,扫秒新串的height数组. 考查后缀数组+LCP #inclu ...
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)
题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...
- UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
随机推荐
- thinkphp5配合datatable插件分页后端处理程序
thinkphp5配合datatable插件分页后端处理程序第一版DataTable.php v.1.0 <?php use think\Db; /** * DataTable.php. */ ...
- java实现两个json的深度对比
两个json的深度对比 在网上找了好多资料都没有找到想要的,还是自己写个吧! 上代码!!! 1.pom.xml中加入 <dependency> <groupId>com.ali ...
- nyoj 244-16进制的简单运算 (scanf("%x%c%x", &a, &b, &c); printf("%o", a ± b))
244-16进制的简单运算 内存限制:64MB 时间限制:1000ms 特判: No 通过数:12 提交数:13 难度:1 题目描述: 现在给你一个16进制的加减法的表达式,要求用8进制输出表达式的结 ...
- pug参考文档
1. API express框架的渲染模板有多种选择,官方的例子是Pug,网上找了一下,Pug没有可以参考的中文文档,于是自己动手丰衣足食.翻译水平一般,各位凑合着看吧. 1.1 开始 安装 通过np ...
- python学习基础—day01
一. python是什么? 优势:简单, 可以跨平台 劣势:执行效率没有C语言那么高 python是解释型语言,逐行编译解释,在不同的系统windows与Linux,需要不同的解释器来编译. 而编译型 ...
- 领扣(LeetCode)两句话中的不常见单词 个人题解
给定两个句子 A 和 B . (句子是一串由空格分隔的单词.每个单词仅由小写字母组成.) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的. 返回所有不常用单 ...
- 勾股数专题-SCAU-1079 三角形-18203 神奇的勾股数(原创)
勾股数专题-SCAU-1079 三角形-18203 神奇的勾股数(原创) 大部分的勾股数的题目很多人都是用for来便利,然后判断是不是平方数什么什么的,这样做的时候要对变量类型和很多细节都是要掌握好的 ...
- 设计模式之美学习(九):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
我们都知道,很多业务系统都是基于 MVC 三层架构来开发的.实际上,更确切点讲,这是一种基于贫血模型的 MVC 三层架构开发模式. 虽然这种开发模式已经成为标准的 Web 项目的开发模式,但它却违反了 ...
- Java基础IO类之字节输入输出流
一.IO流概述 1.IO流:输入输出流(Input/Output) 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象,即数据在设备间的传输流, 流的本质是数据传输,根据数据传输特性将 ...
- String类对象两种实例化方式比较
第一种:直接赋值 String str = "hello!" ; 在java中,有一个字符串常量池,对于这种直接赋值的,会直接写进常量池(常量池里面不存在其value,) 自JD ...