题目:http://poj.org/problem?id=3294

Life Forms

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 18549   Accepted: 5454

Description

You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such as height, colour, wrinkles, ears, eyebrows and the like. A few bear no human resemblance; these typically have geometric or amorphous shapes like cubes, oil slicks or clouds of dust.

The answer is given in the 146th episode of Star Trek - The Next Generation, titled The Chase. It turns out that in the vast majority of the quadrant's life forms ended up with a large fragment of common DNA.

Given the DNA sequences of several life forms represented as strings of letters, you are to find the longest substring that is shared by more than half of them.

Input

Standard input contains several test cases. Each test case begins with 1 ≤ n ≤ 100, the number of life forms. n lines follow; each contains a string of lower case letters representing the DNA sequence of a life form. Each DNA sequence contains at least one and not more than 1000 letters. A line containing 0 follows the last test case.

Output

For each test case, output the longest string or strings shared by more than half of the life forms. If there are many, output all of them in alphabetical order. If there is no solution with at least one letter, output "?". Leave an empty line between test cases.

Sample Input

3
abcdefg
bcdefgh
cdefghi
3
xxx
yyy
zzz
0

Sample Output

bcdefg
cdefgh ?

Source

题意概括:

给出 N 个字符串,求其中出现次数超过 N/2 次的最长公共子串,如果有多种输出多种。

解题思路:

做法依然是二分答案长度,关键在于判断条件有两个:

①出现次数是否大于 N/2,这个通过height分组,统计一下即可。

②当前所枚举的子串不仅要求不能重叠,而且要满足来源于原本不同的字符串(因为合并了所有字符串,所以以原来字符串分区,判断两个子串要在不同区)

二分不重叠相同子串的加强版,网上很多版本都是暴力 O( n ) 判断子串是否来自不同串的,复杂度有点爆炸。

这道题复杂度的优化关键在于优化这个判断条件。

有个技巧:合并字符串时在中间加入分隔标志,后面通过 O(1) 标记即可判断是否满足区间要求。

输出子串的话,只要保存满足条件的 sa 即可。

AC code:

 #include <set>
#include <map>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define LL long long
#define inc(i, j, k) for(int i = j; i <= k ; i++)
#define mem(i, j) memset(i, j, sizeof(i))
#define gcd(i, j) __gcd(i, j)
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
using namespace std;
const int MAXN = 3e5+;
const int maxn = 3e5+;
int r[MAXN];
int wa[MAXN], wb[MAXN], wv[MAXN], tmp[MAXN];
int sa[MAXN]; //index range 1~n value range 0~n-1
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a + l] == r[b + l];
} void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x = wa, *y = wb, *ws = tmp;
for (i = ; i < m; i++) ws[i] = ;
for (i = ; i < n; i++) ws[x[i] = r[i]]++;
for (i = ; i < m; i++) ws[i] += ws[i - ];
for (i = n - ; i >= ; i--) sa[--ws[x[i]]] = i;
for (j = , p = ; p < n; j *= , m = p)
{
for (p = , i = n - j; i < n; i++) y[p++] = i;
for (i = ; i < n; i++)
if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = ; i < n; i++) wv[i] = x[y[i]];
for (i = ; i < m; i++) ws[i] = ;
for (i = ; i < n; i++) ws[wv[i]]++;
for (i = ; i < m; i++) ws[i] += ws[i - ];
for (i = n - ; i >= ; i--) sa[--ws[wv[i]]] = y[i];
for (swap(x, y), p = , x[sa[]] = , i = ; i < n; i++)
x[sa[i]] = cmp(y, sa[i - ], sa[i], j) ? p - : p++;
}
} int Rank[MAXN]; //index range 0~n-1 value range 1~n
int height[MAXN]; //index from 1 (height[1] = 0)
void calheight(int *r, int *sa, int n)
{
int i, j, k = ;
for (i = ; i <= n; ++i) Rank[sa[i]] = i;
for (i = ; i < n; height[Rank[i++]] = k)
for (k ? k-- : , j = sa[Rank[i] - ]; r[i + k] == r[j + k]; ++k);
return;
} int N;
string tp;
vector<int>ans_id;
int f[MAXN], kase; bool check(int limit, int n, int len)
{
bool flag = false;
int cnt = ;
ans_id.clear();
f[sa[]/len] = kase;
for(int i = ; i <= n; i++){
if(height[i] < limit){ //按height分组
f[sa[i]/len] = ++kase; //给区间标记上组的标号
cnt = ;
}
else{
if(f[sa[i]/len] != kase){ //判断一组中是否有相同区间
f[sa[i]/len] = kase;
if(cnt>=) cnt++;
if(cnt > N/){
flag = true;
ans_id.push_back(sa[i]);
cnt = -;
}
}
}
}
return flag;
} int main()
{
bool book = false;
int ssize, n_len = , ans;
while(~scanf("%d", &N) && N){
n_len = ;
kase = ;
ans = ;
for(int i = ; i <= N; i++){
cin >> tp;
ssize = tp.size();
for(int k = ; k < ssize; k++){
r[n_len++] = tp[k]+;
}
r[n_len++] = i; //作分隔标记
}
n_len--;
r[n_len] = ; da(r, sa, n_len+, );
calheight(r, sa, n_len); int L = , R = ssize+, mid;
while(L <= R){
mid = (L+R)>>;
if(check(mid, n_len, ssize+)){
L = mid+;
ans = mid;
}
else R = mid-;
}
check(ans, n_len, ssize+); if(book) puts("");
if(ans == ) puts("?");
else{
int len = ans_id.size();
// printf("%d\n", len);
for(int i = ; i < len; i++){
for(int k = ans_id[i]; k-ans_id[i]+ <= ans; k++){
printf("%c", r[k]-);
}
puts("");
}
}
if(!book) book = true;
}
return ;
}

422ms 3300k

POJ 3294 Life Forms [最长公共子串加强版 后缀数组 && 二分]的更多相关文章

  1. cogs249 最长公共子串(后缀数组 二分答案

    http://cogs.pro:8080/cogs/problem/problem.php?pid=pxXNxQVqP 题意:给m个单词,让求最长公共子串的长度. 思路:先把所有单词合并成一个串(假设 ...

  2. 【poj1226-出现或反转后出现在每个串的最长公共子串】后缀数组

    题意:求n个串的最长公共子串,子串出现在一个串中可以是它的反转串出现.总长<=10^4. 题解: 对于每个串,把反转串也连进去.二分长度,分组,判断每个组. #include<cstdio ...

  3. 【poj3294-不小于k个字符串中最长公共子串】后缀数组

    1.注意每两个串之间的连接符要不一样. 2.分组的时候要注意最后一组啊!又漏了! 3.开数组要考虑连接符的数量.100010是不够的至少要101000. #include<cstdio> ...

  4. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

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

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

  6. poj 1458 Common Subsequence_最长公共子串

    题意:略 求最长公共子串 #include<iostream> #include<cstdio> #include<string> using namespace ...

  7. SPOJ1811最长公共子串问题(后缀自动机)

    题目:http://www.spoj.com/problems/LCS/ 题意:给两个串A和B,求这两个串的最长公共子串. 分析:其实本题用后缀数组的DC3已经能很好的解决,这里我们来说说利用后缀自动 ...

  8. 【wikioi】3160 最长公共子串(后缀自动机)

    http://codevs.cn/problem/3160/ sam的裸题...(之前写了spoj上另一题sam的题目,但是spoj被卡评测现在还没评测完QAQ打算写那题题解时再来详细介绍sam的.. ...

  9. CODE【VS】3160 最长公共子串 (后缀自动机)

    3160 最长公共子串 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Outp ...

随机推荐

  1. Java计算两个经纬度间的距离最简单的方式

    开发中经常会遇到计算两个点(经纬度)之间的距离或者计算最近门店的场景,下面简单实现一下如何计算两个经纬度之间相隔的距离. 1.导入geodesy的maven依赖 或者到阿里云maven仓库下载jar包 ...

  2. MyBatis入门(一)—— 入门案例

    一.MyBatis简介 MyBatis是面向sql的持久层框架,他封装了jdbc访问数据库的过程,我们开发,只需专注于sql语句本身的拼装,其它赋值的过程全部可以交给MyBatis去完成. 与Hibe ...

  3. iReport(模版) 与Jasper(数据填充)生成pdf文档

    报表模板生成软件:iReport . 润乾.水晶. 一.Jaspersoft iReport Desiginer 5.60 的使用 1.软件jar包的下载地址与配置 百度云盘下载链接:https:// ...

  4. Ubuntu Grub 配置跟新

    自从上了Grub2,就开始装逼了,配置不如以前方便了. 需要修改一些基本的配置如菜单超时之类的可以修改/etc/default/grub文件,然后使用update-grub来更新/boot/grub/ ...

  5. js-权威指南学习笔记15

    第十五章 脚本化文档 1.文档对象模型DOM是表示和操作HTML和XML文档内容的基础API. 2.Document.Element.Text是Node的子类. 3.查询文档的一个或多个元素有如下方法 ...

  6. 或许你并不需要jQuery

    此文为翻译文章,原文链接:you might not need jquery jQuery 和它的相关插件都是很强大的,使用它们让我们的应用开发变得简单.如果你正在开发另一个库,请花点时间思考以下,你 ...

  7. MIPS rop gadgets记录贴&&持续更新

    前言 本帖记录一些常用的,效果好的 rop gadgets. uClibc 从栈中设置$t9 并跳到 $t9 的gadgets , __thread_start 函数第二行 使用 案例 使用tips: ...

  8. 功能强大的StickyHeaderListView:标题渐变、吸附悬停、筛选分类、动态头部

    StickyHeaderListView 主要是通过 ListView 添加头部实现,将复杂的头部分解为若干部分,如下图:Header 1(广告位).Header 2(频道位).Header 3(运营 ...

  9. spring <context:annotation-config/> 注解作用

    <context:component-scan>包含<context:annotation-config/>的作用 <context:annotation-config/ ...

  10. Oracle数据库通过DBLINK实现远程访问

    什么是DBLINK? dblink(Database Link)数据库链接顾名思义就是数据库的链接  ,就像电话线一样,是一个通道,当我们要跨本地数据库,访问另外一个数据库表中的数据时,本地数据库中就 ...