uva 11107 Life Forms
题意:给你N个串,求一个串在大于等于N/2的模板串中连续出现。如果有多解按字典序最小输出。
白书模板题。二分答案+合并模板串成一个新串,扫秒新串的height数组。
考查后缀数组+LCP
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int maxn = * + ; struct SuffixArray
{
int s[maxn]; // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)
int sa[maxn]; // 后缀数组
int rank[maxn]; // 名次数组. rank[0]一定是n-1,即最后一个字符
int height[maxn]; // height数组
int t[maxn], t2[maxn], c[maxn]; // 辅助数组
int n; // 字符个数 void clear()
{
n = ;
memset(sa, , sizeof(sa));
} // m为最大字符值加1。调用之前需设置好s和n
void build_sa(int m)
{
int i, *x = t, *y = t2;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[i] = s[i]]++;
for(i = ; i < m; i++) c[i] += c[i-];
for(i = n-; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= )
{
int 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++) c[i] = ;
for(i = ; i < n; i++) c[x[y[i]]]++;
for(i = ; i < m; i++) c[i] += c[i-];
for(i = n-; i >= ; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ;
x[sa[]] = ;
for(i = ; i < n; i++)
x[sa[i]] = y[sa[i-]]==y[sa[i]] && y[sa[i-]+k]==y[sa[i]+k] ? p- : p++;
if(p >= n) break;
m = p;
}
} void build_height()
{
int i, j, k = ;
for(i = ; i < n; i++) rank[sa[i]] = i;
for(i = ; i < n; i++)
{
if(k) k--;
int j = sa[rank[i]-];
while(s[i+k] == s[j+k]) k++;
height[rank[i]] = k;
}
}
}; const int maxc = + ; // 串的个数
const int maxl = + ; // 每个串的长度 SuffixArray sa;
int n;
char word[maxl];
int idx[maxn];
int flag[maxc]; // 子串[L,R) 是否符合要求
bool good(int L, int R)
{
memset(flag, , sizeof(flag));
if(R - L <= n/) return false;
int cnt = ;
for(int i = L; i < R; i++)
{
int x = idx[sa.sa[i]];
if(x != n && !flag[x])
{
flag[x] = ;
cnt++;
}
}
return cnt > n/;
} void print_sub(int L, int R)
{
for(int i = L; i < R; i++)
printf("%c", sa.s[i] - + 'a');
printf("\n");
} bool print_solutions(int len, bool print)
{
int L = ;
for(int R = ; R <= sa.n; R++)
{
if(R == sa.n || sa.height[R] < len) // 新开一段
{
if(good(L, R))
{
if(print) print_sub(sa.sa[L], sa.sa[L] + len);
else
return true;
}
L = R;
}
}
return false;
} void solve(int maxlen)
{
if(!print_solutions(, false))
printf("?\n");
else
{
int L = , R = maxlen, M;
while(L < R)
{
M = L + (R-L+)/;
if(print_solutions(M, false)) L = M;
else R = M-;
}
print_solutions(L, true);
}
} // 给字符串加上一个字符,属于字符串i
void add(int ch, int i)
{
idx[sa.n] = i;
sa.s[sa.n++] = ch;
} int main()
{
int kase = ;
while(scanf("%d", &n) == && n)
{
if(kase++ > ) printf("\n");
int maxlen = ;
sa.clear();
for(int i = ; i < n; i++)
{
scanf("%s", word);
int sz = strlen(word);
maxlen = max(maxlen, sz);
for(int j = ; j < sz; j++)
add(word[j] - 'a' + , i);
add( + i, n); // 结束字符
}
add(, n); if(n == ) printf("%s\n", word);
else
{
sa.build_sa( + n);
sa.build_height();
solve(maxlen);
}
}
return ;
}
uva 11107 Life Forms的更多相关文章
- 后缀数组LCP + 二分 - UVa 11107 Life Forms
Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...
- 后缀数组 UVA 11107 Life Forms
题目链接 题意:训练指南P223 分析:二分长度,把所有字符串连成一个字符串,中间用不同的字符分隔(这是为了保证匹配长度始终在一个字符串内).height数组分段,vis数组标记哪些字符串被访问了,如 ...
- UVA - 11107 Life Forms (广义后缀自动机)
题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 对这n个字符串建广义后缀自动机,建完后每个字符串在自动机上跑一遍,沿fail树向上更新所有子串结点的出现次数( ...
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)
题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...
- UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
- UVa 11107 (后缀数组 二分) Life Forms
利用height值对后缀进行分组的方法很常用,好吧,那就先记下了. 题意: 给出n个字符串,求一个长度最大的字符串使得它在超过一半的字符串中出现. 多解的话,按字典序输出全部解. 分析: 在所有输入的 ...
- UVA - 11107:Life Forms
后缀数组height+二分 #include<cstdio> #include<cstdlib> #include<algorithm> #include<c ...
- UVA 11107(Life Forms-后缀数组+二分)
Problem C: Life Forms You may have wondered why most extraterrestrial life forms resemble humans, di ...
随机推荐
- oracle新建用户
说明:以下命令在PLSQL中运行 一.以管理员身份登录PLSQL scott/root as sysdba 二.创建新用户 create user extjsTest1 identified by r ...
- [JavaScript] js 判断闰年
/** * 判断闰年函数 * @param {number} year 要判断的年份 * @return {bool} 返回布尔值 * * 其实只要满足下面几个条件即可. * 1.普通年能被4整除且不 ...
- Android开发之onClick事件的三种写法(转)
package a.a; import android.app.Activity; import android.os.Bundle; import android.view.View; import ...
- SDK更新问题解决
更新C:\WINDOWS\system32\drivers\etc\host文件百试不爽 第一步 打开SDK Manager下Tools->Options,选中“Force https://… ...
- PHP程序员函数注释规格
<?php/*** @name 名字* @abstract 申明变量/类/方法* @access 指明这个变量.类.函数/方法的存取权限* @author 函数作者的名字和邮箱地址* @cate ...
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)
公司内部同事分享的一篇文章 周末看到一个用jstack查看死锁的例子.昨天晚上总结了一下jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令.供大家参考 1.Jstack 1.1 ...
- java:I/O 一行一行读取和写入
BufferedReader逐行读取 import java.io.*; class Test { public static void main(String args []){ FileReade ...
- CodeForces114E——Double Happiness(素数二次筛选)
Double Happiness On the math lesson a teacher asked each pupil to come up with his own lucky numbers ...
- 企业级 Linux 安全管理实例(1)
公司企业多用Linux服务器,其中涉及到的一些安全管理对于安全运维人员来说是必不可少的应知技能, 以下案例沿着背景->需求->具体要求->操作步骤的流程进行描述,可以加深对安全管理的 ...
- foreman1.3安装
一.环境: centos 6.3 64bit 二.安装yum源: rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release ...