题意:

给定 n 个字符串,求出现在不小于 k 个字符串中的最长子串。

分析:

将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。

然后二分答案,将后缀分成若干组,判断每组的后缀是否出现在不小于 k 个的原串中。

如果是大于127, char 是负数, 在计数排序的时候是会出问题的。

这题在输出上WA了很多次。最后下载了数据才找出来的。。。。

// File Name: 3294.cpp
// Author: Zlbing
// Created Time: 2013年09月07日 星期六 16时21分37秒 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
//rank从0开始
//sa从1开始,因为最后一个字符(最小的)排在第0位
//height从2开始,因为表示的是sa[i-1]和sa[i]
const int MAXN=;
int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN];
int s[MAXN];
int buc[MAXN];
int T[MAXN];
void calheight(int n) {
int i , j , k = ;
for(i = ; i <= n ; i++) rank[sa[i]] = i;
for(i = ; i < n ; height[rank[i++]] = k)
for(k?k--: , j = sa[rank[i]-] ; s[i+k] == s[j+k] ; k++);
}
bool cmp(int *r,int a,int b,int l) {
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
void suffix(int n,int m = ) {
int i , l , p , *x = X , *y = Y;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[i] = s[i] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[i] ]] = i;
for(l = ,p = ; p < n ; m = p , l *= ) {
p = ;
for(i = n-l ; i < n ; i ++) y[p++] = i;
for(i = ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[y[i]] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
for(swap(x,y) , x[sa[]] = , i = , p = ; i < n ; i ++)
x[ sa[i] ] = cmp(y,sa[i-],sa[i],l) ? p- : p++;
}
calheight(n-);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来
}
int vis[];
bool solve(int x,int k,int n)
{
CL(vis,);
vis[]=;
int tot=;
if(!vis[T[sa[]]])
tot++;
vis[T[sa[]]]=;
for(int i=;i<=n;i++)
{
if(height[i]<x)
{
tot=;
CL(vis,);
vis[]=;
if(!vis[T[sa[i]]])
tot++;
vis[T[sa[i]]]=;
continue;
}
if(!vis[T[sa[i]]])tot++;
if(tot>=k)return true;
vis[T[sa[i]]]=;
}
return false;
}
void print(int x,int k,int n)
{
CL(vis,);
int tot=;
vis[]=;
if(!vis[T[sa[]]])
tot++;
vis[T[sa[]]]=;
for(int i=;i<=n;i++)
{
if(height[i]<x)
{
if(tot>=k)
{
for(int j=;j<x;j++)
printf("%c",s[sa[i-]+j]-);
printf("\n");
}
tot=;
CL(vis,);
vis[]=;
if(!vis[T[sa[i]]])
tot++;
vis[T[sa[i]]]=;
continue;
}
if(!vis[T[sa[i]]])tot++;
vis[T[sa[i]]]=;
}
//这里一开始没写导致WA了很多次
if(tot>=k)
{
for(int j=;j<x;j++)
printf("%c",s[sa[n]+j]-);
printf("\n");
}
}
int main() {
//freopen("C.dat","r",stdin);
//freopen("Cout.dat","w",stdout);
int N;
char ch[];
int first=;
while(~scanf("%d",&N))
{
if(!N)break;
if(first)printf("\n");
first++;
int k=N/+;
int n=;
int tt=;
int L=,R=;
REP(i,,N)
{
scanf("%s",ch);
int len=strlen(ch);
R=max(R,len);
REP(j,,len-)
{
s[n++]=(int)ch[j]+;
T[n-]=i;
}
s[n++]=tt++;
T[n-]=;
}
//printf("case %d:",first);
if(N==)
{
printf("%s\n",ch);
continue;
}
s[n-]=;
T[n-]=;
n--;
suffix(n+,);
int ans=-;
while(L<=R)
{
int mid=L+(R-L+)/;
if(solve(mid,k,n))
{
ans=max(ans,mid);
L=mid+;
}
else R=mid-;
}
//printf("%d\n",ans);
if(ans!=-)
print(ans,k,n);
else printf("?\n");
}
return ;
}

POJ-3294-Life Forms(后缀数组-不小于 k 个字符串中的最长子串)的更多相关文章

  1. poj 3294 后缀数组 多字符串中不小于 k 个字符串中的最长子串

    Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 16223   Accepted: 4763 Descr ...

  2. Life Forms POJ - 3294(不小于k个字符串中的最长子串)

    题意: 求不小于字符串一半长度个字符串中的最长字串 解析: 论文题例11 将n个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开, 求后缀数组, 然后二分答案变为判定性问题, 然后判断每组的 ...

  3. 【POJ 3294】Life Forms 不小于k个字符串中的最长子串

    一下午和一晚上都在刚这道题,各种错误都集齐了so sad 我的时间啊!!! 后缀数组就先做到这里吧,是在伤不起啊QAQ 出现了各种奇怪的错误,看了标算,然后乱改自己的代码,莫名其妙的改A了,后来发现用 ...

  4. UVa 11107 生命的形式(不小于k个字符串中的最长子串)

    https://vjudge.net/problem/UVA-11107 题意:给定n个字符串,求出现在不小于n的一半个字符串的最长子串,如果有多个,则按字典序输出. 思路: 首先就是将这n个字符串连 ...

  5. Life Forms (poj3294 后缀数组求 不小于k个字符串中的最长子串)

    (累了,这题做了很久!) Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 8683   Accepted ...

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

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

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

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

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

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

  9. 【poj3294-不小于k个字符串中最长公共子串】后缀数组

    1.注意每两个串之间的连接符要不一样. 2.分组的时候要注意最后一组啊!又漏了! 3.开数组要考虑连接符的数量.100010是不够的至少要101000. #include<cstdio> ...

随机推荐

  1. Socket.IO 概述

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3826251.html ...

  2. URAL 2032 - Conspiracy Theory and Rebranding【本源勾股数组】

    [题意] 给出三角形的三个边长,均是10^7以内的整数,问三角形的三个角的坐标是否能均是整数,输出其中任意一个解. [题解] 一开始想的是枚举一条边的横坐标,然后通过勾股定理以及算角度求出其他点的坐标 ...

  3. [HNOI2012] 矿场搭建

    /* codevs 1996 连通性问题 Tarjan+割点 可以感性的想一想 一定炸割点最好 否则 没有什么影响 先求出割点来 对于剩下的点们 缩一下 当然不能包括割点 这里的缩 因为删了割点就不是 ...

  4. angularJS function

    angular.bootstrap 启动Angular angular.element 相当于轻量的JQuery 使用方法: angular.element('#qq'); angular.eleme ...

  5. 第一次用Github desktop(mac)提交代码遇到的问题

    1.新建代码仓库 2.生成密钥 ssh-keygen -C 'your@email.address' -t rsa 3.到根目录下的.ssh文件夹下找到id_rsa.pub文件,将里面的内容复制到下图 ...

  6. ios进行打包

    原文转载:http://blog.csdn.net/azhou_hui/article/details/9058677   公司刚搞了个299美刀的仅提供真机测试的企业账号,这个不需要添加设备ID,而 ...

  7. 移动端touchstar、touchmove、touchend 事件如果页面有滚动时不让触发 touchend 事件。

    /*仅适用于内容中点击元素.对于拖动等元素,需要自行在页面处理. * 主要是绑定touchstart和touchmove事件,并判断用户按下之后手指移动了多少像素. * 如果手指移动距离小于10像素, ...

  8. CSS居中的方法总结

    [水平居中] 行内:text-align:center; 定宽块状:1.left:0 right:0然后用margin: auto外边距填充,水平方向不会发生外边距叠加;  2.绝对定位(父元素定位不 ...

  9. 基于nodejs的消息中心

    参考:http://t42dw.iteye.com/blog/1767013

  10. (一)Nodejs - 框架类库 - Nodejs异步流程控制Async

    简介 Async是一个流程控制工具包,提供了直接而强大的异步功能 应用场景 业务流程逻辑复杂,适应异步编程,减少回调的嵌套 安装 npm insatll async 函数介绍 Collections ...