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 ...
随机推荐
- js学习之函数表达式及闭包
来自<javascript高级程序设计 第三版:作者Nicholas C. Zakas>的学习笔记(七) 直接切入主题~ 定义函数的方式有两种: 函数声明 function functio ...
- c++: 获取delete[]中的数组大小
看一个小例子: 1 #include <iostream> 2 3 using namespace std; 4 5 class A { 6 public: 7 A() { ...
- POJ 2193 Lenny's Lucky Lotto Lists (DP)
题目链接 题意 : 给你两个数N和M,让你从1到M中找N个数组成一个序列,这个序列需要满足的条件是后一个数要大于前一个数的两倍,问这样的序列有多少,输出. 思路 : dp[i][j]代表着长度为 i ...
- 全选与反选(dom与jquery比较)
<html> <head> <title>全选或反选(dom)</title> <meta http-equiv="Content-Ty ...
- c++ string c_str() 和data()区别
看下面的英文解释: const char* c_str ( ) const;Get C string equivalentGenerates a null-terminated sequence of ...
- 【转】linux C++ 获取文件信息 stat函数详解
stat函数讲解 表头文件: #include <sys/stat.h> #include <unistd.h>定义函数: int stat ...
- 使用头文件climits中的符号常量获知整型数据的表数范围---gyy整理
在头文件climits(limits.h)以宏定义的方式定义了各种符号常量来表示各种整型类型表示数的范围,如int的最大最小值,long的最大最小值等. 符号常量 表示 CHAR_BIT char 的 ...
- Delphi里的RTTI与反射(举例换掉FOnChange)
Delphi2010之后的RTTI做了很大休整,现在用起来很爽了哦.甚至可以获取某些类的内部私有单元,然后为其赋值!讲这个RTTI增强的,可以参考网上的多个博客内容,我列举一下:Delphi2010R ...
- jquery uploadify上传文件插件导致浏览器崩溃问题解决方法
自谷歌浏览器更新到(版本39.0.2171.99 )后,访问上传文件界面浏览器就崩溃了,而其他的浏览器不会出现问题. 出现这种问题的原因就是谷歌浏览器缓存问题,但将访问该jsp页面路径添加上时间戳后无 ...
- java编解码技术,json序列化与二进制序列化
1.何为json序列化与二进制序列化 通常我们在程序中采用的以json为传输,将json转为对象的就是json序列化了.而二进制序列化通常是我们将数据转换为二进制进行传输,然后在进行各类转换操作 2. ...