利用height值对后缀进行分组的方法很常用,好吧,那就先记下了。

题意:

给出n个字符串,求一个长度最大的字符串使得它在超过一半的字符串中出现。

多解的话,按字典序输出全部解。

分析:

在所有输入的字符串后面加一个原串中没有的且互不相同的字符,然后将新得到的n个字符串拼接成一个长的字符串。(为什么要加互不相同的分割字符,这里始终想不明白)

首先二分最大公共字串的长度p。扫描一遍height数组,每遇到一个height[i] < p便开辟一个新段,这样就将height数组拆分为若干段。而且每一段的所有字符都有一个长度为p的公共前缀。只要某一段中包含了超过 n / 2 的原串的后缀,就满足条件了。

如何判断是否包含了某个原串的后缀,用一个flag标记数组即可实现。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = * + ; struct SuffixArray
{
int s[maxn];
int sa[maxn];
int rank[maxn];
int height[maxn];
int t[maxn], t2[maxn], c[maxn];
int n; void clear() { n = ; memset(sa, , sizeof(sa)); } void build_sa(int m)
{
int i, *x = t, *y = t2;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[i] = s[i]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= )
{
int p = ;
for(i = n - k; i < n; i++) y[p++] = i;
for(i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[y[i]]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ; x[sa[]] = ;
for(i = ; i < n; i++)
x[sa[i]] = y[sa[i]]==y[sa[i-]] && y[sa[i]+k]==y[sa[i-]+k] ? p - : p++;
if(p >= n) break;
m = p;
}
} void build_height()
{
int i, j, k = ;
for(i = ; i < n; i++) rank[sa[i]] = i;
for(i = ; i < n; i++)
{
if(k) k--;
j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
}
}; const int maxc = + ;
const int maxl = + ;
SuffixArray sa;
int n;
char word[maxl];
int idx[maxn];
bool flag[maxc]; void print_sub(int L, int R)
{
for(int i = L; i < R; i++) printf("%c", sa.s[i] - + 'a');
puts("");
} bool good(int L, int R)
{
memset(flag, false, sizeof(flag));
int cnt = ;
for(int i = L; i < R; i++)
{
int x = idx[sa.sa[i]];
if(x != n && !flag[x]) { flag[x] = true; cnt++; }
}
return cnt > n / ;
} bool print_solution(int len, bool print)
{
int L = ;
for(int R = ; R <= sa.n; R++)
{
if(R == sa.n || sa.height[R] < len)
{
if(good(L, R))
{
if(print) print_sub(sa.sa[L], sa.sa[L] + len);
else return true;
}
L = R;
}
}
return false;
} void solve(int maxlen)
{
if(!print_solution(, false)) puts("?");
else
{
int L = , R = maxlen, M;
while(L < R)
{
M = L + (R - L + ) / ;
if(print_solution(M, false)) L = M;
else R = M - ;
}
print_solution(L, true);
}
} void add(int ch, int i)
{
idx[sa.n] = i;
sa.s[sa.n++] = ch;
} int main()
{
//freopen("in.txt", "r", stdin); int kase = ;
while(scanf("%d", &n) == && n)
{
if(kase++ > ) puts("");
sa.clear();
int maxlen = ;
for(int i = ; i < n; i++)
{
scanf("%s", word);
int sz = strlen(word);
maxlen = max(maxlen, sz);
for(int j = ; j < sz; j++) add(word[j] - 'a' + , i);
add(i + , n);
}
add(, n); sa.build_sa( + n);
sa.build_height();
solve(maxlen);
} return ;
}

代码君

UVa 11107 (后缀数组 二分) Life Forms的更多相关文章

  1. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

  2. BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案

    BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单 ...

  3. 【bzoj4310】跳蚤 后缀数组+二分

    题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...

  4. BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)

    题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...

  5. POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)

    洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...

  6. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  7. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

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

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

  9. POJ 3294 Life Forms(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...

随机推荐

  1. 批量安装操作系统之cobbler

    Cobbler 部署文档 服务端配置 操作系统:Centos6.4 关闭防火墙及 selinux 安装cobbler软件 添加yum源 rpm -Uvh https://dl.fedoraprojec ...

  2. Grid分组特性

    Ext.onReady(function () {                Ext.define('personInfo', {                    extend: 'Ext. ...

  3. main函数和启动例程

    为什么汇编程序的入口是_start,而C程序的入口是main函数呢?本节就来解释这个问题.在讲例 18.1 “最简单的汇编程序”时,我们的汇编和链接步骤是: $ as hello.s -o hello ...

  4. 分布式数据存储 - MySQL双主复制

    上篇文章<分布式数据存储 - MySQL主从复制>,我们说到MySQL主从复制很好的保障了从库,读的高可用性.so,问题来了: 1.针对主库,写的高可用性又是如何做到高可用性? 2.如果需 ...

  5. 由浅入深了解Thrift之微服务化应用架构

    为什么选择微服务 一般情况下,业务应用我们都会采用模块化的分层式架构,所有的业务逻辑代码最终会在一个代码库中并统一部署,我们称这种应用架构为单体应用. 单体应用的问题是,全部开发人员会共享一个代码库, ...

  6. HDU 2669 Romantic(扩展欧几里德, 数学题)

    题目 //第一眼看题目觉得好熟悉,但是还是没想起来//洪湖来写不出来去看了解题报告,发现是裸的 扩展欧几里得 - - /* //扩展欧几里得算法(求 ax+by=gcd )//返回d=gcd(a,b) ...

  7. Activity学习(五)——Bundle机制

    上一篇文章我简单介绍了Activity之间简单切换,很简单,这一篇文章我们继续聊Android中程序页面互相跳转的Activity,不过这一次我们在Activity跳转时,携带一些简单的数据,然后在新 ...

  8. css系列-段落首字符下沉、缩进及特殊显示

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 在运行jar时自动加载指定的jar包

    初学Java的人经常遇到的一个问题是:如果一个程序依赖某个文件夹下的一堆jar包,那么启动它的时候就需要在java -cp参数后面一个一个的加上jar包的名称,很不方便. 比如主程序类叫Main,在目 ...

  10. ios开发中超简单抽屉效果(MMDrawerController)的实现

    ios开发中,展示类应用通常要用到抽屉效果,由于项目需要,本人找到一个demo,缩减掉一些不常用的功能,整理出一个较短的实例. 首先需要给工程添加第三方类库 MMDrawerController: 这 ...