相同的题目,输出格式有区别。

给定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 后缀数组的更多相关文章

  1. poj 2774 最长公共子串 后缀数组

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 25752   Accepted: 10 ...

  2. Poj 3294 Life Forms (后缀数组 + 二分 + Hash)

    题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...

  3. 后缀数组LCP + 二分 - UVa 11107 Life Forms

    Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...

  4. UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)

    题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...

  5. UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)

    题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...

  6. [POJ 2774] Long Long Message 【后缀数组】

    题目链接:POJ - 2774 题目分析 题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易. 将两个字符串用特殊字符隔开再连接到一起,求出后缀数组. 可以看出,最长公共子串就是两个字符 ...

  7. POJ 2774 Long Long Message(后缀数组)

    [题目链接] http://poj.org/problem?id=2774 [题目大意] 求最长公共子串 [题解] 将两个串中间嵌一个字符相连,求一遍后缀数组 如果排名相邻的两个后缀的开端是分属于两个 ...

  8. POJ 3693 Maximum repetition substring(后缀数组+ST表)

    [题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+ ...

  9. poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14874   Accepted: 5118 De ...

随机推荐

  1. CSS+DIV命名

    原地址:http://www.cnblogs.com/hylaz/archive/2012/10/27/2742743.html#2521377 页头:header 登录条:loginBar 标志:l ...

  2. Python之turtle库-小猪佩奇

    Python之turtle库-小猪佩奇 #!/usr/bin/env python # coding: utf-8 # Python turtle库官方文档:https://docs.python.o ...

  3. history.go history.back()

    转http://www.mikebai.com/Article/2009-11/757.html <input type=button value=刷新 onclick="window ...

  4. JqueryValidate 修改 为根据ID验证

    <!--修改validate根据ID验证 --> <script type="text/javascript"> if ($.validator) { $. ...

  5. MyBatis 多参问题

    当传入的参数为多个参数时 1 可以不封装为Javabean直接传入,写法如下 public List<XXXBean> getXXXBeanList(String xxId, String ...

  6. (转载)O(N)的素数筛选法和欧拉函数

    转自:http://blog.csdn.net/dream_you_to_life/article/details/43883367 作者:Sky丶Memory 1.一个数是否为质数的判定. 质数,只 ...

  7. 元祖、hash了解、字典、集合

    元祖: 元组跟列表差不多,也是存一组数,只是它一旦创建,便不能再修改,所以又叫只读列表. 创建: names = ('neo', 'mike', 'eric') 特性: # 1.可存放多个值 # 2. ...

  8. 关于android系统启动不同activity默认过渡动画不同的一些认识

    在同一个android设备里,发现不同的app启动时显示的过渡动画是不同的.查看显示不同过渡动画的两个app的源码,其设置的主题都是同一个主题,但是为什么过渡动画效果不同呢?后来发现,activity ...

  9. 博弈论入门题 kiki's game

    Problem Description Recently kiki has nothing to do. While she is bored, an idea appears in his mind ...

  10. FDMemTable内存表操作

    unit Umemtable; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System ...