UVA11107 Life Forms --- 后缀数组
UVA11107 Life Forms
题目描述:
求出出现在一半以上的字符串内的最长字符串。
数据范围:
\(\sum len(string) <= 10^{5}\)
非常坑的题目。
思路非常好想。
构造出后缀数组。
二分出\(len\)后用\(height\)分组
记\(bel(i)\)表示排名为\(i\)后缀属于哪一个串
当同一组内的不同的\(bel(i)\)出现了\(n/2\)时,本组内有一组解。
注意:
每行数据间要打一个空行
#include <cstdio>
#include <cstring>
#include <iostream>
#define sid 200050
#define ri register int
using namespace std; template <typename re>
inline void upmax(re &a, re b) { if(a < b) a = b; } int Tt, n, ml, ned;
char s[sid];
int bel[sid], sc[sid];
int flag[];
int sa[sid], rk[sid], cnt[sid], p1[sid], p2[sid], ht[sid]; inline void Suffix() {
int m = ;
int *t1 = p1, *t2 = p2;
for(ri i = ; i <= n; i ++) sc[i] = (s[i] == ) ? ++ m : s[i];
for(ri i = ; i <= n; i ++) t1[i] = sc[i];
for(ri i = ; i <= m; i ++) cnt[i] = ;
for(ri i = ; i <= n; i ++) cnt[t1[i]] ++;
for(ri i = ; i <= m; i ++) cnt[i] += cnt[i - ];
for(ri i = n; i >= ; i --) sa[cnt[t1[i]] --] = i;
for(ri k = ; k <= n; k <<= ) {
int p = ;
for(ri i = ; i <= m; i ++) t2[i] = ;
for(ri i = n - k + ; i <= n; i ++) t2[++ p] = i;
for(ri i = ; i <= n; i ++) if(sa[i] > k) t2[++ p] = sa[i] - k;
for(ri i = ; i <= m; i ++) cnt[i] = ;
for(ri i = ; i <= n; i ++) cnt[t1[t2[i]]] ++;
for(ri i = ; i <= m; i ++) cnt[i] += cnt[i - ];
for(ri i = n; i >= ; i --) sa[cnt[t1[t2[i]]] --] = t2[i];
swap(t1, t2); t1[sa[]] = p = ;
for(ri i = ; i <= n; i ++)
t1[sa[i]] = (t2[sa[i]] == t2[sa[i - ]] && t2[sa[i] + k] == t2[sa[i - ] + k]) ? p : ++ p;
m = p; if(p >= n) break;
}
for(ri i = ; i <= n; i ++) rk[sa[i]] = i;
ri k = , j;
for(ri i = ; i <= n; i ++) {
if(k) k --;
j = sa[rk[i] - ];
while(sc[j + k] == sc[i + k]) k ++;
ht[rk[i]] = k;
}
} inline bool Check(int htk) {
int cnt = , tim = ;
memset(flag, , sizeof(flag));
for(ri i = ; i <= n; i ++) {
if(ht[i] < htk) cnt = , ++ tim;
if(flag[bel[sa[i]]] != tim && bel[sa[i]]) cnt ++, flag[bel[sa[i]]] = tim;
if(cnt >= ned) return ;
}
return ;
} inline int Binary() {
int l = , r = ml, ans = -;
while(l <= r) {
int mid = (l + r) >> ;
if(Check(mid)) l = mid + , ans = mid;
else r = mid - ;
}
return ans;
} inline void Get_Ans(int op) {
if(op == -) {
printf("?\n");
return;
}
memset(flag, , sizeof(flag));
int cnt = , tim = , fag;
for(ri i = ; i <= n; i ++) {
if(ht[i] < op) fag = , cnt = , ++ tim;
if(flag[bel[sa[i]]] != tim && bel[sa[i]]) cnt ++, flag[bel[sa[i]]] = tim;
if(cnt >= ned && !fag) {
int k = sa[i];
for(ri j = ; j <= op; j ++) printf("%c", s[k + j - ]);
printf("\n");
cnt = ; fag = ;
}
}
} int main() {
bool pe = ;
while(scanf("%d", &Tt) == && Tt) {
if(pe) printf("\n"); pe = ;
n = ml = ; ned = Tt / + ;
memset(s, , sizeof(s));
memset(bel, , sizeof(bel));
for(ri i = ; i <= Tt; i ++) {
scanf("%s", s + + n);
int nl = strlen(s + + n);
for(ri j = n + ; j <= n + nl; j ++) bel[j] = i;
upmax(ml, nl); n += nl; s[++ n] = ;
}
if(Tt != ) {
Suffix();
int ans = Binary();
Get_Ans(ans);
}
else {
for(ri j = ; j <= n - ; j ++) printf("%c", s[j]);
printf("\n");
}
}
return ;
}
打开有惊喜
UVA11107 Life Forms --- 后缀数组的更多相关文章
- POJ3294 Life Forms —— 后缀数组 最长公共子串
题目链接:https://vjudge.net/problem/POJ-3294 Life Forms Time Limit: 5000MS Memory Limit: 65536K Total ...
- Poj 3294 Life Forms (后缀数组 + 二分 + Hash)
题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...
- POJ3294 Life Forms(后缀数组)
引用罗穗骞论文中的话: 将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组的后缀是否出现在不小于k 个的原串中 ...
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串
Life Forms Time Limit: 500 ...
- POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串
Life Forms Description You may have wondered why most extraterrestrial life forms resemble humans, ...
- poj 3294 Life Forms - 后缀数组 - 二分答案
题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...
- 【UVA11107 训练指南】Life Forms【后缀数组】
题意 输入n(n<=100)个字符串,每个字符串长度<=1000,你的任务是找出一个最长的字符串使得超过一半的字符串都包含这个字符串. 分析 训练指南上后缀数组的一道例题,据说很经典(估计 ...
- 后缀数组LCP + 二分 - UVa 11107 Life Forms
Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...
随机推荐
- 【leetcode 简单】第三十三题 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, a plan, a c ...
- Verilog笔记.5.同步、异步
在数字电路中经常有同步synchronism.异步asynchronism的概念.异步指输入信号和时钟无关:同步指输入信号和时钟信号有关,实际上就是输入信号和时钟信号进行了与运算或者与非运算.实际开发 ...
- Linux mint 18.1 / Ubuntu 16.04 安装steam
这里以Limit Mint 18.1为例: 安装steam: sudo dpkg -i steam.deb 运行后会有如下错误: 直接运行如下命令修复, 并自动启动steam: LD_PRELOAD= ...
- shell中$*与$@的区别
$*所有的位置参数,被作为一个单词 注意:"$*"必须被""引用 $@ 与$*同义,但是每个参数都是一个独立的""引用字串,这就意味着参数被 ...
- nginx 各种配置
first : mkdir /usr/local/nginx/conf/vhosts{网站配置}/usr/local/nginx/conf/vhosts/test.conf : server { li ...
- php+mysql缓存技术的实现
本教程适合于那些对缓存SQL查询以减少数据库连接与执行的负载.提高脚本性能感兴趣的PHP程序员.概述 许多站点使用数据库作为站点数据存储的容器.数据库包含了产器信息.目录结构.文章或者留言本,有些数据 ...
- 在delphi原有控件基础上画图
var C:TControlCanvas; begin C := TControlCanvas.Create; C.Pen.Color := clRed; C.Pen.Width := ; C.Con ...
- 20165301 2017-2018-2 《Java程序设计》第七周学习总结
20165301 2017-2018-2 <Java程序设计>第七周学习总结 教材学习内容总结 第十一章:JDBC与MySQL数据库 MySQL数据库管理系统 启动MySQL数据库服务器 ...
- span文字里面自动换行时怎么办
可以用white-space:nowrap来强制文字不换行,知道遇到<br>为止
- python函数库及函数标准库
一.系统库提供的内部函数 字符函数库: 1)str.islower() :字符串是否全部是小写 2)str.isspace() :字符串是否为空 3)help(str):查询字符串函数库 4)str. ...