POJ3294 Life Forms —— 后缀数组 最长公共子串
题目链接:https://vjudge.net/problem/POJ-3294
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 16905 | Accepted: 4970 |
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+1个字符串中的公共子串。如果存在,输入长度最大的;如果有多个答案,按字典序输出所有。
题解:
1.将n个字符串拼接在一起,并且相邻两个之间用分隔符隔开,并且分隔符应各异。因此得到新串。
2.求出新串的后缀数组,然后二分公共子串的长度mid:可知当前的mid可将新串的后缀按排名的顺序将其分成若干组,且每一组的最长公共前缀都大于等于mid,于是就在每一组内统计出现了多少个字符串,如果>n/2,即表明当前mid合法,否则不合法,因此可以根据此规则最终求得长度。
3.由于题目还要求按字典序输出所有答案。所以,在求得长度之后,再遍历一遍sa[]数组,并且判断每个分组是否满足要求,若满足,则输出答案。
注意点:
1.每个分隔符应该不一样,如果一样,在求后缀数组的时候就很可能从当前字符串匹配到下一个字符串,而这是不可能的,因为对于每个字符,最多只能匹配到串尾。
2.输出答案时,为了避免同一组内多次输出(每一组对应着一个子串),应该加个标记。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 2e5+; int id[MAXN]; //记录属于哪个字符串
int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
int t1[MAXN], t2[MAXN], c[MAXN]; bool cmp(int *r, int a, int b, int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
{
n++;
int i, j, p, *x = t1, *y = t2;
for(i = ; i<m; i++) c[i] = ;
for(i = ; i<n; i++) c[x[i] = str[i]]++;
for(i = ; i<m; i++) c[i] += c[i-];
for(i = n-; i>=; i--) sa[--c[x[i]]] = i;
for(j = ; j<=n; j <<= )
{
p = ;
for(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<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]] = cmp(y, sa[i-], sa[i], j)?p-:p++; if(p>=n) break;
m = p;
} int k = ;
n--;
for(i = ; i<=n; i++) Rank[sa[i]] = i;
for(i = ; i<n; i++)
{
if(k) k--;
j = sa[Rank[i]-];
while(str[i+k]==str[j+k]) k++;
height[Rank[i]] = k;
}
} bool vis[];
bool test(int n, int len, int k)
{
int cnt = ;
memset(vis, false, sizeof(vis));
for(int i = ; i<=len; i++)
{
if(height[i]<k)
{
cnt = ;
memset(vis, false, sizeof(vis));
}
else
{
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]] = true, cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]] = true, cnt++;
if(cnt>n/) return true;
}
}
return false;
} void Print(int n, int len, int k)
{
int cnt = , flag = false;
memset(vis, false, sizeof(vis));
for(int i = ; i<=len; i++)
{
if(height[i]<k)
{
flag = false;
cnt = ;
memset(vis, false, sizeof(vis));
}
else
{
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]] = true, cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]] = true, cnt++;
if(cnt>n/ &&!flag)
{
flag = true; //表明当前组已经输出了
for(int j = sa[i]; j<sa[i]+k; j++)
putchar(r[j]+'a'-);
putchar('\n');
}
}
}
} char str[MAXN];
int main()
{
int n, firCase = false;
while(scanf("%d", &n)&&n)
{
int len = ;
for(int i = ; i<n; i++)
{
scanf("%s", str);
int LEN = strlen(str);
for(int j = ; j<LEN; j++)
{
r[len] = str[j]-'a'+;
id[len++] = i;
}
r[len] = +i; //分隔符要各异
id[len++] = i;
}
r[len] = ;
DA(r,sa,Rank,height,len,); int l = , r = ;
while(l<=r)
{
int mid = (l+r)>>;
if(test(n,len,mid))
l = mid + ;
else
r = mid - ;
} if(firCase) printf("\n");
firCase = true;
if(r==) puts("?");
else Print(n, len, r);
}
}
POJ3294 Life Forms —— 后缀数组 最长公共子串的更多相关文章
- POJ 2217 (后缀数组+最长公共子串)
题目链接: http://poj.org/problem?id=2217 题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续. 解题思路: 后缀数组解法是这类问题的模板解法. 对 ...
- POJ-2774-Long Long Message(后缀数组-最长公共子串)
题意: 给定两个字符串 A 和 B,求最长公共子串. 分析: 字符串的任何一个子串都是这个字符串的某个后缀的前缀. 求 A 和 B 的最长公共子串等价于求 A 的后缀和 B 的后缀的最长公共前缀的最大 ...
- [poj 2274]后缀数组+最长公共子串
题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是O(nm)的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然 ...
- CSU1632Repeated Substrings(后缀数组/最长公共前缀)
题意就是求一个字符串的重复出现(出现次数>=2)的不同子串的个数. 标准解法是后缀数组.最长公共前缀的应用,对于样例aabaab,先将所有后缀排序: aab 3 aabaab 1 a ...
- POJ3450 Corporate Identity —— 后缀数组 最长公共子序列
题目链接:https://vjudge.net/problem/POJ-3450 Corporate Identity Time Limit: 3000MS Memory Limit: 65536 ...
- POJ3294 Life Forms(后缀数组)
引用罗穗骞论文中的话: 将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组的后缀是否出现在不小于k 个的原串中 ...
- POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数
题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS Memory Limit: 65536K ...
- [SPOJ1811]Longest Common Substring 后缀自动机 最长公共子串
题目链接:http://www.spoj.com/problems/LCS/ 题意如题目,求两个串的最大公共子串LCS. 首先对其中一个字符串A建立SAM,然后用另一个字符串B在上面跑. 用一个变量L ...
- POJ 2774 (后缀数组 最长公共字串) Long Long Message
用一个特殊字符将两个字符串连接起来,然后找最大的height,而且要求这两个相邻的后缀的第一个字符不能在同一个字符串中. #include <cstdio> #include <cs ...
随机推荐
- Ubuntu下安装JDK图文解析
我们在64位的Ubuntu中安装JDK,选择的是jdk1.6.0_32版本号.安装文件名称为jdk-6u32-linux-x64.bin(这个是64位系统的),假设是32位系统的还须要去官网下载32位 ...
- 【Python】使用制表符换行符来添加空白
在编程中,在打印时,有时候需要显示出来的数据看着舒服一点,那么使用制表符(\t).换行符(\n)即可轻松实现 >>> print('zhangsan')zhangsan 加入制表符后 ...
- android权限申请Permission
代码地址如下:http://www.demodashi.com/demo/12432.html android在6.0系统以后,权限申请变得麻烦起来,今天介绍一个超级好用的权限申请库,我在使用中经过再 ...
- 面试题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变?
/* * 问题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变 * 答: * 使用finalkeyword修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内 ...
- setTimeout()基础/setInterval()基础
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...
- jquery代码小片段
1. 使用jQuery来切换样式表 //找出你希望切换的媒体类型(media-type),然后把href设置成新的样式表. $(‘link[media="screen"]‘).at ...
- JS批量获取参数构建JSON参数对象
在做系统的时候,往往查询条件是被严格指定的,大量的查询条件,一两个页面还可以通过dom去一个一个获取,再构建参数对象,请求后台接口. 这里给大家讲一个批量获取前端参数,构建参数对象. <form ...
- 36:字符串排序SortString
题目描述:编写一个程序,将输入字符串中的字符按如下规则排序. 规则1:英文字母从A到Z排列,不区分大小写. 如,输入:Type 输出:epTy 规则2:同一个英文字母的大小写同时存在时,按照输入顺序排 ...
- vsftpd 自动安装脚本
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'cpy' import os import re import sys impo ...
- beego的MVC架构介绍
beego 的 MVC 架构介绍 beego 是一个典型的 MVC 框架,它的整个执行逻辑如下图所示: 通过文字来描述如下: 在监听的端口接收数据,默认监听在 8080 端口. 用户请求到达 8080 ...