POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别。
给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中。
不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517
这道题的思路也是基本相同的,都是利用了后缀数组的良好性质。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std; const int MAX = 100500;
const int nMAX = 105;
const int mMAX = 1005; int strnum;
char str[nMAX][mMAX];
int source[MAX];
int sa[MAX], rk[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];
bool vis[nMAX];
int id[MAX];
int anslen, anspos[mMAX], ansnum;
const int MAXN=200000+100;
void radix(int *str,int *a,int *b,int n,int m)
{
static int count[MAXN];
memset(count,0,sizeof(count));
for(int i=0;i<n;++i)++count[str[a[i]]];
for(int i=1;i<=m;++i)count[i]+=count[i-1];
for(int i=n-1;i>=0;--i)b[--count[str[a[i]]]]=a[i];
} void sorted_suffix_array(int *str,int *sa,int n,int m)
{
static int rank[MAXN],a[MAXN],b[MAXN];
for(int i=0;i<n;++i)rank[i]=i;
radix(str,rank,sa,n,m); rank[sa[0]]=0;
for(int i=1;i<n;++i)rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
for(int i=0;(1<<i) <n;++i)
{
for(int j=0;j<n;++j)
{
a[j]=rank[j]+1;
b[j]=j+(1<<i)>=n? 0:rank[j+(1<<i)]+1;
sa[j]=j;
}
radix(b,sa,rank,n,n);
radix(a,rank,sa,n,n);
rank[sa[0]]=0;
for(int j=1;j<n;++j)
{
rank[sa[j]]=rank[sa[j-1]]+(a[sa[j-1]]!=a[sa[j]]||b[sa[j-1]]!=b[sa[j]]);
}
}
} void calc_height(int *str,int *sa,int *h,int n)
{
static int Rank[MAXN];
int k=0;
h[0]=0;
for(int i=0;i<n;++i)Rank[sa[i]]=i;
for(int i=0;i<n;++i)
{
k= k==0?0:k-1;
if(Rank[i]!=0)
while(str[i+k]==str[sa[Rank[i]-1]+k])++k;
h[Rank[i]]=k;
}
} bool solve(int beg, int end)
{
int tot = 0;
int t = strnum >> 1;
for (int i = 0; i < strnum; ++i) vis[i] = false;
for (int i = beg; i <= end; ++i)
{
if (!vis[id[sa[i]]])
{
vis[id[sa[i]]] = true;
++tot;
}
if (tot > t) return true;
}
return false;
} bool group(int len, int n)
{
bool res = false;
int beg, end;
beg = end = 0;
for (int i = 1; i < n; ++i)
{
if (height[i] >= len) ++end;
else
{
if (solve(beg, end))
{
if (!res) ansnum = 0;
res = true;
anspos[ansnum++] = sa[beg];
}
beg = end = i;
}
}
if (beg < end)
{
if (solve(beg, end))
{
if (!res) ansnum = 0;
res = true;
anspos[ansnum++] = sa[beg];
}
}
return res;
} int main()
{ // freopen("t.txt","r",stdin);
bool flg=false;
while (scanf("%d", &strnum) && strnum != 0)
{ if(flg)printf("\n");
for (int i = 0; i < strnum; ++i) scanf("%s", str[i]);
int n = 0, low = 1, high = 0, mid;
for (int i = 0; i < strnum; ++i)
{
int j;
for (j = 0; str[i][j] != 0; ++j)
{
id[n] = i;
source[n++] = str[i][j] - 'a' + 100;
}
if (j > high) high = j;
id[n] = i;
source[n++] = i;
}
sorted_suffix_array(source,sa,n,126);
calc_height(source,sa,height,n);
//suffix(source, n, 126);
//calheight(source, n - 1);
anslen = 0;
while (low <= high)
{
mid = (low + high) >> 1;
if (group(mid, n))
{
anslen = mid;
low = mid + 1;
}
else high = mid - 1;
}
if (anslen == 0) printf("?\n");
else
{
for (int i = 0; i < ansnum; ++i)
{
for (int j = 0; j < anslen; ++j)
{
printf("%c", source[anspos[i] + j] - 100 + 'a');
}
printf("\n");
}
}
//printf("\n");
flg=true;
}
return 0;
}
POJ 3294 UVA 11107 Life Forms 后缀数组的更多相关文章
- poj 2774 最长公共子串 后缀数组
Long Long Message Time Limit: 4000MS Memory Limit: 131072K Total Submissions: 25752 Accepted: 10 ...
- Poj 3294 Life Forms (后缀数组 + 二分 + Hash)
题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...
- 后缀数组LCP + 二分 - UVa 11107 Life Forms
Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...
- UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)
题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...
- UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
- [POJ 2774] Long Long Message 【后缀数组】
题目链接:POJ - 2774 题目分析 题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易. 将两个字符串用特殊字符隔开再连接到一起,求出后缀数组. 可以看出,最长公共子串就是两个字符 ...
- POJ 2774 Long Long Message(后缀数组)
[题目链接] http://poj.org/problem?id=2774 [题目大意] 求最长公共子串 [题解] 将两个串中间嵌一个字符相连,求一遍后缀数组 如果排名相邻的两个后缀的开端是分属于两个 ...
- POJ 3693 Maximum repetition substring(后缀数组+ST表)
[题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+ ...
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 14874 Accepted: 5118 De ...
随机推荐
- JS 实现全屏预览 F11功能
老是不通过,没办法,只能是重新发布了,反正我就是杠上了,大大小小写过很多前端特效,当然也经常在网上copy或者修改人家的代码,我觉得也挺好的,为什么?!因为我想这样,你能怎么办,打我?少废话,直接上代 ...
- Variational Auto-Encoders原理
目录 AE v.s. VAE Generative model VAE v.s. GAN AE v.s. VAE Generative model VAE v.s. GAN
- Anaconda基本用法
Anaconda基本用法 conda info --envs/(-e) // 查看当前的环境变量 conda create -n py36(环境的名称,随意) python=3.6(指定版本) // ...
- 82-Ichimoku Kinko Hyo 一目平衡表.(2015.7.3)
Ichimoku Kinko Hyo 一目平衡表 计算: 一目平衡图由五组参数合成,与现在常用的移动平均线吻合.参数基于各个长短周期的高低点,提供一明确简单的走势图.五个参数如下: 1.短轴快线 短轴 ...
- LeetCode(4)Median of Two Sorted Arrays
题目 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...
- C语言《一维数组的学习,冒泡排序》
#include<stdio.h> /* 一维数组的学习,冒泡排序 soulsjie 20170623 */ void main(){ int a[6]; int i,j,k; print ...
- MySQL-Transfer2.2发布
http://dinglin.iteye.com/blog/1888640 Transfer 2.2发布.下载地址 版本说明 1. 基于版本 Percona-5.5.31 ,简单用法是先安装好官方或 ...
- [K/3Cloud] 单据转换插件执行顺序
1.下推事件及顺序 //初始化变量 OnInitVariable(InitVariableEventArgs e) //解析字段映射关系,并构建查询参数.这里可以加入你想要的额外的字段 OnQuery ...
- Gym 100801 J. Journey to the “The World’s Start” DP+单调队列优化+二分
http://codeforces.com/gym/100801 题目大意:有从左到右有n个车站,有n-1种车票,第i种车票一次最多可以坐 i 站(1<=i<=n) 每种票有固定的价钱 ...
- hdu - 1704 Rank(简单dfs)
http://acm.hdu.edu.cn/showproblem.php?pid=1704 遇到标记过的就dfs,把隐含的标记,最后计数需要注意. #include <cstdio> # ...