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: 经典题. 直接二分判断答案. 判 ...
随机推荐
- 微信小程序开发(三)项目目录及文件结构
第二章我们已经创建了一个Hello WXapplet示例小程序.我们从文件目录结构来了解Hello WXapplet项目的构成. 目录结构显示,在小程序项目的根目录下面包含3个app开头的文件(app ...
- 【leetcode 简单】第二题 反转整数
给定一个 32 位有符号整数,将整数中的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入: 120 输出: 21 注意: 假 ...
- [Leetcode] Longest Palindromic Subsequence
Longest Palindromic Subsequence 题解 题目来源:https://leetcode.com/problems/longest-palindromic-subsequenc ...
- redis的备份恢复
说明:默认rdb方式保存,redis支持主从和哨兵等,但是在某些情况下我们会单机跑,所以有时候我们就会需要设计到备份恢复 环境:原始redis:192.168.1.200 新redis:192.168 ...
- 设置网卡IP,还每次都挨个地址输入吗?批处理一下【转】
1.设置网卡ip,子网掩码和默认网关,注意修改网卡名称,跟本地连接汇总的网卡名称保持一直 netsh interface ip set address "以太网" static 1 ...
- julia 1.0如何使用pkg
输入]进入pkg模式 add 加包名即可安装,如 add Cxx
- LightOJ 1024 Eid(高精度乘法+求n个数最小公约数)
题目链接:https://vjudge.net/contest/28079#problem/T 题目大意:给你n个数求这些数的最小公倍数(约数). 解题思路:还太菜了,看了别人的题解才会写,转自这里, ...
- Kiggle:Digit Recognizer
题目链接:Kiggle:Digit Recognizer Each image is 28 pixels in height and 28 pixels in width, for a total o ...
- linux crontab 常用时间设置
时间格式 分钟 小时 日期 月份 周 命令 数字范围 0-59 0-23 1-31 1-12 0-7 echo "hello" >> abc.log 特殊字符的含义 * ...
- codeforce 1A Theatre Square
A. Theatre Square Theatre Square in the capital city of Berland has a rectangular shape with the siz ...