poj 3294 Life Forms(后缀数组)
题意:给你最多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(后缀数组)的更多相关文章
- Poj 3294 Life Forms (后缀数组 + 二分 + Hash)
题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...
- poj 3294 Life Forms - 后缀数组 - 二分答案
题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...
- POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串
Life Forms Description You may have wondered why most extraterrestrial life forms resemble humans, ...
- POJ 3294 Life Forms(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...
- POJ 3294 Life Forms [最长公共子串加强版 后缀数组 && 二分]
题目:http://poj.org/problem?id=3294 Life Forms Time Limit: 5000MS Memory Limit: 65536K Total Submiss ...
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- POJ 1743 Musical Theme 后缀数组 最长重复不相交子串
Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description ...
- POJ 1226 Substrings(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=1226 [题目大意] 求在每个给出字符串中出现的最长子串的长度,字符串在出现的时候可以是倒置的. [题解] 我们将每个字符串倒置,用 ...
- POJ 3080 Blue Jeans 后缀数组, 高度数组 难度:1
题目 http://poj.org/problem?id=3080 题意 有m个(2<=m<=10)不包含空格的字符串,长度为60个字符,求所有字符串中都出现过的最长公共子序列,若该子序列 ...
- UVA11107 Life Forms --- 后缀数组
UVA11107 Life Forms 题目描述: 求出出现在一半以上的字符串内的最长字符串. 数据范围: \(\sum len(string) <= 10^{5}\) 非常坑的题目. 思路非常 ...
随机推荐
- Mysql JDBC Url参数说明useUnicode=true&characterEncoding=UTF-8
MySQL的 JDBC URL 格式 for Connector/J 如下例: jdbc:mysql://[host][,failoverhost...][:port]/[database] » [ ...
- 或许有一两点你不知的C语言特性
关键字篇 volatile关键字 鲜为人知的关键字之一volatile,表示变量是'易变的',之所以会有这个关键字,主要是消除编译优化带来的一些问题,看下面的代码 ; int b = a; int c ...
- coder
#include <iostream>#include <GL/glut.h>using std::cout;using std::endl;float windowWidth ...
- ubuntu下Qt之android环境配置以及一些常见问题解决
准备材料有: 1. qt for android 5.×版本,下载地址如下,可以选择一个合适自己机器型号的版本进行下载. 地址:http://www.qt.io/download-open-sourc ...
- 什么是redis数据库?
新公司的第一个项目让用redis.之前没接触过,所以从网上找些文章,学习理解一下 原链接:http://baike.so.com/doc/5063975-5291322.html 什么是redis ...
- Find your present (2) (位异或)
Problem Description In the new year party, everybody will get a "special present".Now it's ...
- typedef与define
一.typedef用法 typedef常用来定义一个标识符及关键字的别名,它生效是在语言编译过程,但它并不实际分配内存空间.typedef可以增强程序的可读性,以及标识符的灵活性,但它也有“非直观性” ...
- C++11的新特性lambda的小试牛刀RAII
C/C++的资源是手动管理的 这导致程序员在申请资源时,最后用完了偶尔会忘记回收 C++语言的发明者倡导RAII,资源获取即初始化 使用对象来管理资源的生命周期,在超出作用域时,析构函数自动释放资源 ...
- 什么是image crop?
一直对image crop很困惑,总算是看到了一篇描述较为简洁的说明:图像crop就是指从图像中移除不需要的信息,只保留需要的部分
- 【产品体验】ONE一个
第二篇博客,加油加油~~本人产品新人,学习中,希望大家多多指教! 先来两张ONE的界面图镇楼—— ONE简介: “复杂世界里,一个就够了.”这是一款轻量级的文艺阅读应用,每日更新一张图 ...