按照以前两个字符串找两者的最长公共子串的思路类似,可以把所有串拼接到一起,这里为了避免讨论LCP跨越多个串需需要特别处理的问题用不同的字符把所有串隔开(因为char只有128位,和可能不够用,更推荐设置成某一特殊字符,在后缀数组初始化的时候在对其映射的int值做处理)。二分长度然后遍历Height,判断SA是否处于同一个串。这里我一开始觉得判断不同串的计数有点麻烦,其实根据LCP确定起点,随终点延伸Height值不会上升的特性,一旦Height小于我们要求的值就切换到下一计数(因为必然不可能再和之前计数的串再产生重合了)。

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <algorithm>
#include <cstdio>
#define debug puts("debug")
#define LL long long
using namespace std; const int N=;
string s,temp;
int nn;
int pos[N];
int vis[N];
int phs[N];
int endp[N];
int stx[N],sp; class SF
{
//N:数组大小
public:
int x[N], y[N], c[N];
int Height[N], str[N], SA[N], Rank[N];//Height数组从2开始,SA记录Rank=i的下标
int slen;
int m;//字符集处理大小(传入如果不是数字,需要做位移转换)
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)
{
++n;
int i, j, p;
for (i = ; i < m; ++i) c[i] = ;
for (i = ; i < n; ++i) c[x[i] = str[i]]++;
for (i = ; i < m; ++i) c[i] += c[i - ];
for (i = n - ; i >= ; --i) SA[--c[x[i]]] = i; for (j = ; j <= n; j <<= )
{
p = ;
for (i = n - j; i < n; ++i) y[p++] = i;
for (i = ; i < n; ++i) if (SA[i] >= j) y[p++] = SA[i] - j;
for (i = ; i < m; ++i) c[i] = ;
for (i = ; i < n; ++i) c[x[y[i]]]++; for (i = ; i < m; ++i) c[i] += c[i - ];
for (i = n - ; i >= ; --i) SA[--c[x[y[i]]]] = y[i]; swap(x, y);
p = ;
x[SA[]] = ;
for (i = ; i < n; ++i)
{
x[SA[i]] = cmp(y, SA[i - ], SA[i], j) ? p - : p++;
}
if (p >= n)break;
m = p;
} int k = ;
n--;
for (i = ; i <= n; ++i) Rank[SA[i]] = i; for (i = ; i < n; ++i)
{
if (k)--k;
j = SA[Rank[i] - ];
while (str[i + k] == str[j + k])++k;
Height[Rank[i]] = k;
//cout << k << endl;
}
}
static const int bitlen = ;
LL lg2(LL p)//计算log2(n)
{
return (LL)(log(p) / log());
}
LL dp[bitlen][N];
LL bit[bitlen];
void initRMQ()//初始化
{
bit[] = ;
for (int i = ; i < bitlen; i++) bit[i] = * bit[i - ];
for (int i = ; i <= slen; i++)
dp[][i] = Height[i];
dp[][] = dp[][] = ;
for (LL i = ; bit[i] < slen + ; i++)
for (LL j = ; j + bit[i] <= slen + ; j++)
dp[i][j] = min(dp[i - ][j], dp[i - ][j + bit[i - ]]);
}
LL query(LL l, LL r)//查询两个Rank之间的lcp
{
if (r == l) return slen - SA[l];
if (l > r) swap(l, r);
l++;
LL mig = lg2(r - l + 1.0);
return min(dp[mig][l], dp[mig][r - bit[mig] + ]);
}
void init(string s)
{
slen = s.size();
m=;//每次都需要初始化m
int fuck=;
for (int i = ; i < slen; i++)
{
if(s[i]!='#')
str[i] = s[i] - 'a' + ;//如果是字符,映射成从1开始的序列
else str[i]=+(fuck++);
}
str[slen] = ;//1作为结束符,防止越界
Suffix(slen); initRMQ();
}
bool ok(int lx)
{
sp=;
fill(vis,vis+slen+,);
int cnt=;
vis[phs[SA[]]]=;
//cout<<phs[1]<<endl;
for(int i=; i<=slen; i++)
{
//cout<<Height[i]<<endl;
//cout<<phs[i]<<endl;
if(Height[i]>=lx)
{
if(vis[phs[SA[i]]]==)
cnt++,vis[phs[SA[i]]]=;
}
else
{
if(cnt>nn/)
stx[sp++]=SA[i-];
cnt=;
fill(vis,vis+nn+,);
vis[phs[SA[i]]]=;
}
}
if(cnt>nn/)
stx[sp++]=SA[slen-];
return sp;
}
int bins(int l,int r)
{
while(r-l>=)
{
int mid=(l+r)/;
if(ok(mid))l=mid;
else r=mid-;
}
//cout<<l<<' '<<r<<endl;
for(; r>=l; r--)
{
//cout<<r<<endl;
if(ok(r))return r;
}
return ;
} void solve()
{
int f=bins(,slen);
if(!f)cout<<"?"<<endl;
else
{
//sort(stx,stx+f,cmp);
for(int i=; i<sp; i++)
{
//cout<<stx[i]<<endl;
for(int j=; j<f; j++)
cout<<s[stx[i]+j];
cout<<endl;
}
}
}
} sf;
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
cin.sync_with_stdio(false);
int cnt=;
while(cin>>nn)
{
if(!nn)break;
if(cnt++)cout<<endl;
s=""; for(int i=; i<nn; i++)
{
cin>>temp;
pos[i]=temp.length();
s+=temp;
s+='#';
}
if(nn==)
{
s=s.substr(,s.length()-);
cout<<s<<endl;
continue;
}
int p=;
for(int i=; i<nn; i++)
{
for(int j=; j<pos[i]; j++,p++)
phs[p]=i;
phs[p++]=nn;
if(i==)endp[i]=pos[i];
else endp[i]=endp[i-]+pos[i]+;
}
sf.init(s); sf.solve();
//sf.ok(1);
}
return ;
}

POJ-3294 Life Forms n个字符串中出现超过n/2次的最长子串(按字典序依次输出)的更多相关文章

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

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

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

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

  3. SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串

    题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags  You ...

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

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

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

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

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

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

  7. 字符串(后缀数组):POJ 3294 Life Forms

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

  8. poj 3415 后缀数组 两个字符串中长度不小于 k 的公共子串的个数

    Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11469   Accepted: 379 ...

  9. poj 3294 Life Forms

    后缀数组的题目,把后缀连接起来,这个还是先二分答案,然后选取一段连续的height值,判断这些height代表的后缀有没有覆盖一半以上的字符串. 得出答案的长度之后还要在枚举连续的heigh,判断有没 ...

随机推荐

  1. IDEA--生成jar包并且导出jar包

    PS:首先在idea中新建一个java文件,且带有main方法(不带有main好像不能导出,不确定) 参考文章:http://www.cnblogs.com/blog5277/p/5920560.ht ...

  2. C++的初始化成员列表

    class CExample { public: int a; float b; //构造函数初始化列表 CExample(): a(),b(8.8) {} //构造函数内部赋值 CExample() ...

  3. css设置input获得焦点的样式

    input:focus{ 样式; } 这样就ok

  4. js $的扩展写法

    (function ($, w) { $.extend({   getRenderList: function (keyword, pageIndex, pageSize, renderEle, re ...

  5. 记录下diagwait的问题

    对于Oracle集群,有关diagwait的解释可以很容易在网上搜到: 该问题只会出现在ORACLE 11.2 以前版本中,在 11G R2版本中,diagwait的值默认配置为13. 而针对11.2 ...

  6. CDN和智能DNS原理和应用 (原)

    CDN是什么? CDN的全称是Content Delivery Network,即内容分发网络. CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡.内容分发.调 ...

  7. 关于绕过域名(ip)校验的一些小知识

    这篇文章最开始只是想写一个关于绕过referer的方法,写着写着发现和ssrf以及url跳转的一些手法类似,于是把这两种也加上了 对referer做校验一般是对csrf进行防范的手段之一,但是很多时候 ...

  8. 第二章 函数和window对象

    1.什么是函数函数相当于Java中的方法,每一个函数可以做一件事情,但是不属于某一个类 2.使用函数的好处:使代码模块化,功能分工明确,方便调用,思路功能清晰 3.函数的分类:(1)系统函数:系统提前 ...

  9. java socket编程实例代码

    1.所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 两性话题 两性 ...

  10. wingIDE Pro6 破解教程

    亲测wingIDE pro6.0.6-1激活成功 算号器下载 激活的时候选择第三项 打开算号器,获得license id 把算号器里的license id输入到第一步的输入框里 continue得到r ...