POJ 3294 Life Forms [最长公共子串加强版 后缀数组 && 二分]
题目: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 [最长公共子串加强版 后缀数组 && 二分]的更多相关文章
- cogs249 最长公共子串(后缀数组 二分答案
http://cogs.pro:8080/cogs/problem/problem.php?pid=pxXNxQVqP 题意:给m个单词,让求最长公共子串的长度. 思路:先把所有单词合并成一个串(假设 ...
- 【poj1226-出现或反转后出现在每个串的最长公共子串】后缀数组
题意:求n个串的最长公共子串,子串出现在一个串中可以是它的反转串出现.总长<=10^4. 题解: 对于每个串,把反转串也连进去.二分长度,分组,判断每个组. #include<cstdio ...
- 【poj3294-不小于k个字符串中最长公共子串】后缀数组
1.注意每两个串之间的连接符要不一样. 2.分组的时候要注意最后一组啊!又漏了! 3.开数组要考虑连接符的数量.100010是不够的至少要101000. #include<cstdio> ...
- POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板
Milk Patterns Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 7586 Accepted: 3448 Cas ...
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单 ...
- poj 1458 Common Subsequence_最长公共子串
题意:略 求最长公共子串 #include<iostream> #include<cstdio> #include<string> using namespace ...
- SPOJ1811最长公共子串问题(后缀自动机)
题目:http://www.spoj.com/problems/LCS/ 题意:给两个串A和B,求这两个串的最长公共子串. 分析:其实本题用后缀数组的DC3已经能很好的解决,这里我们来说说利用后缀自动 ...
- 【wikioi】3160 最长公共子串(后缀自动机)
http://codevs.cn/problem/3160/ sam的裸题...(之前写了spoj上另一题sam的题目,但是spoj被卡评测现在还没评测完QAQ打算写那题题解时再来详细介绍sam的.. ...
- CODE【VS】3160 最长公共子串 (后缀自动机)
3160 最长公共子串 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Outp ...
随机推荐
- UML 类图详解
转载来源:http://blog.csdn.net/shift_wwx/article/details/79205187 可以参考:http://www.uml.org.cn/oobject/2012 ...
- SQL SERVER DATETIME应用
),, , ),); ),, ),); ),, , ),); ),, ),); ),, , ),); ),, ),); How to get first and last day of previou ...
- Django基础四之模板系统
一 语法 模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使 ...
- vue实现上传上删除压缩图片
<script> import {Config} from '@/config.js' import {mapState} from 'vuex' import {LocalData, t ...
- hadoop HA集群搭建步骤
NameNode DataNode Zookeeper ZKFC JournalNode ResourceManager NodeManager node1 √ √ √ √ node2 ...
- 润乾在东方通tongweb5.0上部署手册
作为国内领先的中间件开发商,东方通是国内最早研究J2EE技术和开发应用服务器产品的厂商.应用服务器TongWeb的开发目标,是利用公司在中间件 领域的技术优势,实现符合J2EE规范的企业应用支撑 ...
- linux 网络命令last、lastlog、traceroute、netstat
last /usr/bin/last语法:last功能:列出目前与过去登入系统的用户信息 reboot 是重启信息 lastlog lastlog -u 502(用户ID) traceroute /b ...
- oracle 企业管理器及无线网环境下配置方法
注意: oracle em 的访问地址在 D:\oracle\product\11.2.0\dbhome_1\install 下的文件里. 如果在windows 安装oracle,并且在本地访问,or ...
- web.xml里welcome-file欢迎页面配置及web.xml简介
web项目欢迎页面的配置 <welcome-file-list> <welcome-file>/WEB-INF/index.html</welcome-file> ...
- insufficient privileges for 'SYS' when 'shutdown immediate'
SQL> select * from v$version; BANNER------------------------------------------------------------- ...