题目链接

题意:训练指南P223

分析:二分长度,把所有字符串连成一个字符串,中间用不同的字符分隔(这是为了保证匹配长度始终在一个字符串内)。height数组分段,vis数组标记哪些字符串被访问了,如果可行,更新长度最大值,以及所有符合条件的子串的起点,最后要按字典序从小到大输出。虽然写的有些搓,比LRJ慢几倍,其中还有RE,WA等错误,但是通过自己的思考与debug,终于AC还是很开心的。

#include <bits/stdc++.h>

const int N = 1001 * 100 + 5;
char s[N];
int sa[N], rank[N], height[N];
int ws[N], wa[N], wb[N]; bool cmp(int *r, int a, int b, int l) {
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
void DA(char *r, int n, int m = 128) {
int i, j, p, *x = wa, *y = wb;
for (i=0; i<m; ++i) ws[i] = 0;
for (i=0; i<n; ++i) ws[x[i]=r[i]]++;
for (i=1; i<m; ++i) ws[i] += ws[i-1];
for (i=n-1; i>=0; --i) sa[--ws[x[i]]] = i;
for (j=1, p=1; p<n; j<<=1, m=p) {
for (p=0, i=n-j; i<n; ++i) y[p++] = i;
for (i=0; i<n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i=0; i<m; ++i) ws[i] = 0;
for (i=0; i<n; ++i) ws[x[y[i]]]++;
for (i=1; i<m; ++i) ws[i] += ws[i-1];
for (i=n-1; i>=0; --i) sa[--ws[x[y[i]]]] = y[i];
std::swap (x, y);
for (p=1, x[sa[0]]=0, i=1; i<n; ++i) {
x[sa[i]] = cmp (y, sa[i-1], sa[i], j) ? p - 1 : p++;
}
}
}
void calc_height(char *r, int *sa, int n) {
int i, j, k = 0;
for (i=1; i<=n; ++i) rank[sa[i]] = i;
for (i=0; i<n; ++i) {
if (k) k--;
j = sa[rank[i]-1];
while (r[i+k] == r[j+k]) k++;
height[rank[i]] = k;
}
} std::vector<int> lens;
bool vis[105];
int m; bool ok() {
int ret = 0;
for (int i=0; i<m; ++i) {
if (vis[i]) {
ret++;
}
if (ret > m / 2) {
return true;
}
}
return false;
} bool check(int len, int n, std::vector<int> &fs) {
bool flag = false, nex = true;
int pos = -1;
for (int i=1; i<=n; ++i) {
if (s[sa[i-1]] == '$' || s[sa[i]] == '$') {
continue;
}
if (height[i] >= len) {
if (pos == -1) {
memset (vis, false, sizeof (vis));
}
int loc = std::lower_bound (lens.begin (), lens.end (), sa[i-1]) - lens.begin ();
vis[loc] = true;
loc = std::lower_bound (lens.begin (), lens.end (), sa[i]) - lens.begin ();
vis[loc] = true;
pos = sa[i];
if (nex && ok ()) {
fs.push_back (pos);
flag = true;
nex = false;
}
} else {
pos = -1;
nex = true;
}
}
return flag;
} int main() {
srand (time (NULL));
int cas = 0;
while (scanf ("%d", &m) == 1) {
if (!m) {
break;
}
if (cas++ > 0) {
puts ("");
}
int n = 0;
lens.clear ();
for (int i=0; i<m; ++i) {
scanf ("%s", s + n);
n = strlen (s);
lens.push_back (n);
s[n++] = '$' + rand () % 10;
}
n--;
DA (s, n + 1);
calc_height (s, sa, n);
int left = 1, right = n;
std::vector<int> froms, fs;
int best = 0;
while (left <= right) {
int mid = left + right >> 1;
fs.clear ();
if (check (mid, n, fs)) {
if (best < mid) {
best = mid;
froms.clear ();
for (auto p: fs) {
froms.push_back (p);
}
}
left = mid + 1;
} else {
right = mid - 1;
}
}
std::vector<std::string> ans;
if (best > 0) {
std::string tmp = "";
for (int j=0; j<froms.size (); ++j) {
int L = froms[j] + best;
tmp = "";
for (int i=froms[j]; i<L; ++i) {
//printf ("%c", s[i]);
tmp += s[i];
}
ans.push_back (tmp);
}
std::sort (ans.begin (), ans.end ());
for (auto a: ans) {
std::cout << a << '\n';
}
} else {
puts ("?");
}
}
return 0;
}

  

后缀数组 UVA 11107 Life Forms的更多相关文章

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

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

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

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

  3. UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)

    题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...

  4. UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)

    题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...

  5. uva 11107 Life Forms

    题意:给你N个串,求一个串在大于等于N/2的模板串中连续出现.如果有多解按字典序最小输出. 白书模板题.二分答案+合并模板串成一个新串,扫秒新串的height数组. 考查后缀数组+LCP #inclu ...

  6. UVA - 11107 Life Forms (广义后缀自动机)

    题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 对这n个字符串建广义后缀自动机,建完后每个字符串在自动机上跑一遍,沿fail树向上更新所有子串结点的出现次数( ...

  7. 后缀数组练习4:Life Forms

    有一个细节不是特别懂,然后的话细节有点多,就是挺难发现的那一种,感谢大佬的博客 1470: 后缀数组4:Life Forms poj3294 时间限制: 1 Sec  内存限制: 128 MB提交: ...

  8. UVA 12206 - Stammering Aliens(后缀数组)

    UVA 12206 - Stammering Aliens 题目链接 题意:给定一个序列,求出出现次数大于m,长度最长的子串的最大下标 思路:后缀数组.搞出height数组后,利用二分去查找就可以 这 ...

  9. UVA11107 Life Forms --- 后缀数组

    UVA11107 Life Forms 题目描述: 求出出现在一半以上的字符串内的最长字符串. 数据范围: \(\sum len(string) <= 10^{5}\) 非常坑的题目. 思路非常 ...

随机推荐

  1. IOS- 内存管理机制

    iOS平台内存常见问题 作为iOS平台的开发者,是否曾经为内存问题而苦恼过?内存莫名的持续增长,程序莫名的crash,难以发现 的内存泄漏,这些都是iOS平台内存相关的常见问题:本文将会详细介绍iOS ...

  2. 使用Apache+Dreamweaver(或者H-builder)搭建php开发环境

    使用得工具说明 php+Apache服务器+Dreamweaver+mysql数据库 下载安装好wamp,可以在网上直接百度下载,为了方便,我给放个百度云的链接.wamp下载:链接:http://pa ...

  3. Retrofit与RXJava整合

    Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API.下面我用对比的方式来介绍 Retrofit 的 RxJava 版 ...

  4. 前端模板artTemplate,handlerbars的使用心得

    写前端页面肯定离不开模板渲染,就近期项目中用的两个前端模板做一些使用总结,顺便复习一下,也方便后面温故. 1,artTemplate 优点: 1,一般web端用得较多,执行速度通常是 Mustache ...

  5. Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- ApiWrapper

    前面两片文章讲解了通过AIDL和Messenger两种方式实现Android IPC.而本文所讲的并不是第三种IPC方式,而是对前面两种方式进行封装,这样我们就不用直接把Aidl文件,java文件拷贝 ...

  6. elk安装(这个是初级的可以把这个套件安上)

    http://udn.yyuap.com/doc/logstash-best-practice-cn/index.html ELK其实并不是一款软件,而是一整套解决方案,是三个开源软件Elastics ...

  7. 无废话Android之内容观察者ContentObserver、获取和保存系统的联系人信息、网络图片查看器、网络html查看器、使用异步框架Android-Async-Http(4)

    1.内容观察者ContentObserver 如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调 ...

  8. Gmail 账号找回办法

    前段时间一直在用GFW代理,结果发现GOOGLE账户的保护机制起用了,要给以前的手机号发消息,结果哪个号现在不用了,所以就登陆不进去了,非常扯淡,索性谷歌了下,得出如下的解决方案,完美解决,下次直接在 ...

  9. JS手机浏览器判断(转)

    整理查询一下,js判断手机浏览器的方法 <script type="text/javascript"> /* * 智能机浏览器版本信息:包括微信内置 * */ var ...

  10. java.lang.UnsupportedClassVersionError: org/xwiki/xxx : Unsupported major.minor version 51.0

    此类问题主要是因为Unsupported major.minor version 51.0. 原因是JDK版本不一致导致的问题.在web应用中碰到此问题. 应用中规定使用JDK7.0,本地JDK为6. ...