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 --- 后缀数组的更多相关文章

  1. POJ3294 Life Forms —— 后缀数组 最长公共子串

    题目链接:https://vjudge.net/problem/POJ-3294 Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total ...

  2. Poj 3294 Life Forms (后缀数组 + 二分 + Hash)

    题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...

  3. POJ3294 Life Forms(后缀数组)

    引用罗穗骞论文中的话: 将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组的后缀是否出现在不小于k 个的原串中 ...

  4. POJ 3294 UVA 11107 Life Forms 后缀数组

    相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...

  5. POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串

                                                                              Life Forms Time Limit: 500 ...

  6. POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串

    Life Forms   Description You may have wondered why most extraterrestrial life forms resemble humans, ...

  7. poj 3294 Life Forms - 后缀数组 - 二分答案

    题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...

  8. 【UVA11107 训练指南】Life Forms【后缀数组】

    题意 输入n(n<=100)个字符串,每个字符串长度<=1000,你的任务是找出一个最长的字符串使得超过一半的字符串都包含这个字符串. 分析 训练指南上后缀数组的一道例题,据说很经典(估计 ...

  9. 后缀数组LCP + 二分 - UVa 11107 Life Forms

    Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...

随机推荐

  1. 天梯赛 L2-009 抢红包

    题目链接 没有人没抢过红包吧-- 这里给出N个人之间互相发红包.抢红包的记录,请你统计一下他们抢红包的收获. 输入格式: 输入第一行给出一个正整数N(<= 104),即参与发红包和抢红包的总人数 ...

  2. IDEA常见错误

    1. inspects a maven model for resolution problems 在添加Maven依赖的时候,报了inspects a maven model for resolut ...

  3. 服务器端包含 SSI简介

    服务器端包含 SSI,是英文 Server Side Includes的简写.SSI是一种可以指挥服务器动态声称网页内容的HTML指令. 通常SSI可以用来确保网页中的一些通用内容,比如版权信息.联系 ...

  4. jquery.cookie.js——jquery的cookie插件

    一.JS文件 /*! * jQuery Cookie Plugin v1.4.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2 ...

  5. 蓝色的oa模板html_综合信息服务管理平台OA模板——后台

    链接:http://pan.baidu.com/s/1qXGGOAK 密码:2otu

  6. 有关mysql的innodb_flush_log_at_trx_commit参数【转】

    一.参数解释 0:log buffer将每秒一次地写入log file中,并且log file的flush(刷到磁盘)操作同时进行.该模式下在事务提交的时候,不会主动触发写入磁盘的操作. 1:每次事务 ...

  7. Vue.js写一个SPA登录页面的过程

    技术栈 vue.js 主框架 vuex 状态管理 vue-router 路由管理 一般过程 在一般的登录过程中,一种前端方案是: 检查状态:进入页面时或者路由变化时检查是否有登录状态(保存在cooki ...

  8. oracle造成系统CPU过高的检查sql

    1. 根据占用CPU高的进程号来查询这个进程执行的SQL语句: CPU过高的进程号: #首先找到CPU过高的进程号 # top -bn1 是静态找到占用最高的进程 [root@localhost ~] ...

  9. 最小的Django应用

    创建一个hello.py   内容如下: import sys from django.conf import settings # 设置 settings.configure( DEBUG = Tr ...

  10. nginx配置--event模块

    在nginx的配置中,event模块可以进行以下配置: 设置网络连接的序列化. 在Nginx服务器的多进程下,有可能出现惊群(Thundering herd problem)问题,指的是当某一个时刻只 ...