题意:给你最多100个字符串,求最长的且是一半以上的字符串的公共子串,如果有多个,按字典序输出。

思路:先把各个串拼起来,中间加上一个之前未出现过的字符,然后求后缀。然后根据h数组和sa数组,求出最长的公共串。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using std::sort;
#define V 220000
int r[V],sa[V],h[V],a[V],b[V],X[V],Y[V];
int acl[120],len[110],tot,mark[V],mark_len,be[V],m[110],max_len;
char s[V],out1[V],out2[V];
void calh(int n)
{
int i,j,k=0;
for(i=1; i<=n; i++)r[sa[i]]=i;
for(i=0; i<n; h[r[i++]]=k)
for(k? k-- :0,j=sa[r[i]-1];a[i+k]==a[j+k];k++);
}
bool cmp(int *r,int a,int b,int le)
{
return (r[a]==r[b]&&r[a+le]==r[b+le]);
}
void suffix(int n,int m=128)
{
int i,j,*x=X,*y=Y,*t,p;
for(i=0;i<m;i++)b[i]=0;
for(i=0;i<n;i++)b[x[i]=a[i]]++;
for(i=1;i<m;i++)b[i]+=b[i-1];
for(i=n-1;i>=0;i--)sa[--b[x[i]]]=i;
for(j=1,p=1;p<n;m=p,j<<=1)
{
p=0;
for(i=n-j;i<n;i++)y[p++]=i;
for(i=0; i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0; i<m;i++)b[i]=0;
for(i=0; i<n;i++)b[x[y[i]]]++;
for(i=1; i<m;i++)b[i]+=b[i-1];
for(i=n-1;i>=0;i--)sa[--b[x[y[i]]]]=y[i];
for(t=x,x=y,y=t,x[sa[0]]=0,i=1,p=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
calh(n-1);
}
void judge(int n)//先预处理每个sa属于哪个串
{
int i,j,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=tot;j++)
{
if(sa[i]==len[j]){
be[i]=0;
break;
}
if(sa[i]<len[j]){
be[i]=j;
break;
}
}
}
}
int mm[110];
int getmin(int s)//排序得到当前最长的公共串长度
{
for(int i=1;i<=tot;i++)mm[i]=m[i];
sort(mm+1,mm+1+tot);
return mm[tot+1-s];
}
void solve(int n)
{
int cou=tot/2+1,cur=0,cur_len=0,i,j;//cou表示至少需要的串的数量,cur表示目前的子串所在的串的数量,cur_len表示目前子串的长度
judge(n);
memset(m,0,sizeof(m));//m表示各个串包含的子串的长度
for(i=1;i<=n;i++)
{
for(j=1;j<=tot;j++)if(m[j]>h[i])//更新mi
m[j]=h[i];
if(h[i]<max_len){
cur=0;continue;
}
if(h[i]>m[be[i]]){
if(m[be[i]]==0||m[be[i]]<max_len)cur++;
m[be[i]]=h[i];
}
if(h[i]>m[be[i-1]]){
if(m[be[i-1]]==0||m[be[i-1]]<max_len)cur++;
m[be[i-1]]=h[i];
}
if(cur>=cou){
cur_len=getmin(cou);
if(cur_len>max_len)
{
mark_len=1;
mark[0]=sa[i];
max_len=cur_len;
}
else if(cur_len==max_len)
mark[mark_len++]=sa[i];
}
}
}
int main()
{
int i,j,k,t,n;
for(i=1;i<=96;i++)acl[i]=i;
for(i=97;i<=110;i++)acl[i]=i+26;
while(scanf("%d",&t)!=-1&&t)
{
len[0]=-1;
for(i=1;i<=t;i++)
{
scanf("%s",s+len[i-1]+1);
len[i]=strlen(s);
s[len[i]]=acl[i];
}
s[len[t]]=0;
n=strlen(s);
for(i=0;i<n;i++)a[i]=s[i];
a[n]=0;
suffix(n+1);
mark_len=0;max_len=0;tot=t;
solve(n);
if(max_len==0)
printf("?\n\n");
else{
strcpy(out1,s+mark[0]);
out1[max_len]=0;
puts(out1);
for(i=1;i<mark_len;i++){
strcpy(out2,s+mark[i]);
out2[max_len]=0;
if(strcmp(out1,out2)==0)continue;
strcpy(out1,out2);
puts(out1);
}
puts("");
}
}
return 0;
}

poj 3294 Life Forms(后缀数组)的更多相关文章

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

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

  2. poj 3294 Life Forms - 后缀数组 - 二分答案

    题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...

  3. POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串

    Life Forms   Description You may have wondered why most extraterrestrial life forms resemble humans, ...

  4. POJ 3294 Life Forms(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...

  5. POJ 3294 Life Forms [最长公共子串加强版 后缀数组 && 二分]

    题目:http://poj.org/problem?id=3294 Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submiss ...

  6. POJ 3294 UVA 11107 Life Forms 后缀数组

    相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...

  7. POJ 1743 Musical Theme 后缀数组 最长重复不相交子串

    Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description ...

  8. POJ 1226 Substrings(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=1226 [题目大意] 求在每个给出字符串中出现的最长子串的长度,字符串在出现的时候可以是倒置的. [题解] 我们将每个字符串倒置,用 ...

  9. POJ 3080 Blue Jeans 后缀数组, 高度数组 难度:1

    题目 http://poj.org/problem?id=3080 题意 有m个(2<=m<=10)不包含空格的字符串,长度为60个字符,求所有字符串中都出现过的最长公共子序列,若该子序列 ...

  10. UVA11107 Life Forms --- 后缀数组

    UVA11107 Life Forms 题目描述: 求出出现在一半以上的字符串内的最长字符串. 数据范围: \(\sum len(string) <= 10^{5}\) 非常坑的题目. 思路非常 ...

随机推荐

  1. 在CAD中怎么画圆形视口的详细说明

    方法如下:在布局下画一个合适的圆,然后:命令: _-vports指定视口的角点或[开(ON)/关(OFF)/布满(F)/消隐出图(H)/锁定(L)/对象(O)/多边形(P)/恢复(R)/2/3/4]& ...

  2. 存储过程修改产品描述页图片alt描述信息

    今天修改了所有产品的图片信息,用到了存储过程.在参考下面存储过程以后,终于搞定了. 1 BEGIN 2 DECLARE Done INT DEFAULT 0; 3 4 DECLARE CurrentL ...

  3. OOS升级服务

    给我们的应用程序做个版本更新服务,展示一个安装程序如何实现自动更新. //服务组,添加需要的任何服务 public enum ServerEnum { AutoupdateService,//自动升级 ...

  4. C#编写自动关机程序复习的知识

    首先一个程序第一要素是logo 在设置里面可以设置程序图标,在ICON里设置. ICON图标可以在网上下载. 这些都是表面功夫 程序中涉及到Buton.Label.Timer.Notiflcon控件 ...

  5. C语言实现五子棋简单功能

    /******************************************************************** C-4.29-1: 实现五子棋游戏 操作说明:用方向键或者& ...

  6. ASP.NET MVC轻教程 Step By Step 4——Model、View和Controller

    ASP.NET MVC中的Model(数据模型)主要包括定义数据结构.数据库读写.数据验证等等和对象处理相关的工作. 在解决方案资源管理器中找到Model文件夹,点击右键,添加一个新类,名为“Mess ...

  7. jdk各个版本

    http://www.cnblogs.com/langtianya/p/3757993.html

  8. Hdu 3177 Crixalis's Equipment

    Crixalis's Equipment Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  9. 7 Tools for Data Visualization in R, Python, and Julia

    7 Tools for Data Visualization in R, Python, and Julia Last week, some examples of creating visualiz ...

  10. Python on Android

    Python on Android Posted on April 29, 2015 by Alexander Taylor   There are an increasing number of r ...