题目链接

题意:训练指南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. php继承、多态

    继承: 概念:子类可以继承父类的一切 特点:单继承:一个子类只能有一个父类,一个父类可以派生出多个子类 方法重写:在子类里面对父类的方法进行重写. 重写:override 重载,编译多态:overlo ...

  2. The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.

    出现这样的错误: error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your C ...

  3. 解决Idea创建maven-archetype-webapp项目无java目录的问题

    一.背景 在适用IDEA创建maven-archetype-webapp项目的时候,创建完成后发现在main文件夹下没有java源文件夹,不少小伙伴也遇到该问题,但不知道怎么解决,下面我就来分享解决步 ...

  4. linux rpm问题:怎样查看rpm安装包的安装路径

      x rpm问题:怎样查看rpm安装包的安装路径 2010-07-12 21:19:15 标签:rpm linux 路径 休闲 职场 rpm -qpl xxxxxx.rpm 1.如何安装rpm软件包 ...

  5. 二、JavaScript语言--JS基础--JavaScript进阶篇--JavaScript内置对象

    1.什么事对象 JavaScript 中的所有事物都是对象,如:字符串.数值.数组.函数等,每个对象带有属性和方法. 对象的属性:反映该对象某些特定的性质的,如:字符串的长度.图像的长宽等: 对象的方 ...

  6. JS中级 - 02:表单、表格

    getElementsByTagName() getElementsByTagName() 方法可返回带有指定标签名的对象的集合. getElementsByClassName() 返回文档中所有指定 ...

  7. java的final用法

    转自:http://blog.163.com/maomaoyu_1012/blog/static/19060130520116269329894/ 1.         修饰基础数据成员的final ...

  8. 实现VS2010整合NUnit进行单元测试(转载)

    代码编写,单元测试必不可少,简单谈谈Nunit进行单元测试的使用方式: 1.下载安装NUnit(最新win版本为NUnit-2.6.4.msi) http://www.nunit.org/index. ...

  9. 【翻译十】java-固定锁和同步

    Intrinsic Locks and Synchronization Synchronization is built around an internal entity known as the  ...

  10. [LeetCode] Word Break II (TLE)

    Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...