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序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
随机推荐
- 201871010114-李岩松《面向对象程序设计(java)》第六、七周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- canvas画圆环%显示
我: JS代码: function circleProgress(id,value,average){ var canvas = document.getElementById(id); var ...
- 微信APP支付【签名失败】
最近在做微信APP支付 遇到一个问题 请求预下单时,接口返回签名错误 由于之前没有成功的交互,刚开始检查程序的错误,经过多次修改,发现依然是签名错误,可能出现的问题如下: 1.该签名密钥不是AppSe ...
- 编译spark支持thriftserver
cdh默认把spark的spark-sql以及hive-thriftserver给弃用掉了,想玩玩thriftserver,于是自己重新编译一个 官网参考: http://spark.apache.o ...
- TreeMap的源码学习
TreeMap的源码学习 一).TreeMap的特点 根据key值进行排序. 二).按key值排序的两种排序算法实现 1).在构造方法中传入比较器 public TreeMap(Comparator& ...
- python_07
破解极限滑动认证 from selenium import webdriver from selenium.webdriver import ActionChains from PIL import ...
- 线程池的C++实现(一)
现代的软件一般都使用了多线程技术,在有些软件里面,一个线程被创建出来执行了仅仅一个任务,然后就被销毁了.线程的创建与销毁是需要消耗资源,这样为了执行单一任务而被创建出来的线程越多,性能也就越差.如果能 ...
- Win 使用终端创建mysql数据库及使用(5)
删除你创建过的数据库newsql里面的所有表 这里必须安装了mysql,并且知道用户名密码IP地址.因为我用的window,所以只介绍Win使用cmd创建的方式 首先windown+R 出现窗口输入c ...
- Java方法之定义形式及可变参数
目录 Java方法之定义形式及可变参数 方法调用 使用static修饰的方法 没有static修饰的方法 方法的定义格式 无参无返 无参有返 有参无返 有参有返 形参个数可变的方法 采用数组形参来定义 ...
- Linux的awk命令详解
awkawk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,默认以空格为分隔符将每行切片,切开的部分再 ...