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 ...
随机推荐
- 【转】JS前台加密,java后台解密实现
因项目需求,需要一些敏感信息进行加密,不能以明文暴露到浏览器. 然后后台进行解密操作 先看一下效果图 未对其加密传输 1.前台JS <script type="text/javascr ...
- python开发必备神器 Virtualenv及管理工具Virtualenvwrapper
如果在一台机器上,想开发多个不同的项目,需要用到同一个包的不同版本,如果还在本地继续安装,在同一个目录下安装或者更新,其它的项目必须就无法运行了,怎么办呢? 解决方案:虚拟环境 虚拟环境可以搭建独立的 ...
- whistle替代Fiddler调试远程服务器代码使用教程
前沿 之前在window下开发的同学大部分都是使用Fiddler代理工具做远程调试,自从换了Mac后也想找个代替工具调试,查询了下大概都比较推荐两款:Charles 和 Whistle .不过Char ...
- css画一个提示框
用css画一个如下图的提示框: 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- drupal7 hook_validate
原文:function hook_validate function hook_validate($node, $form, &$form_state) { if (isset($node-& ...
- hallo world
- pom.xml 如果使用 mvn exec:exec 命令运行项目
pom.xml 如果使用 mvn exec:exec 命令运行项目,红色字体要与groupid相同 <project xmlns="http://maven.apache.org/PO ...
- with admin option /with grant option
1. with admin option是用在系统权限上的,with grant option是用在对象权限上的. SQL> grant create synonym to scott with ...
- 转: Dubbo远程调用服务框架原理与示例
Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring 框架无缝集成. 主要核心部件: Remoting: 网络通 ...
- 解决initializing java tooling(1%)
这是wtp的一个bug,下载附件runtimePatch_327801.zip,解压,放到eclipse下,重启就好了.