SPOJ - PHRASES Relevant Phrases of Annihilation (后缀数组)
You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages concerning the date of the planned attack on your island. You immedietaly send for the Bytelandian Cryptographer, but he is currently busy eating popcorn and claims that he may only decrypt the most important part of the text (since the rest would be a waste of his time). You decide to select the fragment of the text which the enemy has strongly emphasised, evidently regarding it as the most important. So, you are looking for a fragment of text which appears in all the messages disjointly at least twice. Since you are not overfond of the cryptographer, try to make this fragment as long as possible.
Input
The first line of input contains a single positive integer t<=10, the number of test cases. t test cases follow. Each test case begins with integer n (n<=10), the number of messages. The next n lines contain the messages, consisting only of between 2 and 10000 characters 'a'-'z', possibly with some additional trailing white space which should be ignored.
Output
For each test case output the length of longest string which appears disjointly at least twice in all of the messages.
Example
Input:
1
4
abbabba
dabddkababa
bacaba
baba Output:
2
(in the example above, the longest substring which fulfills the requirements is 'ba')
题意:
每个字符串至少出现两次且不重叠的最长子串的长度
思路:
二分答案,按height分组,记录同一组内同一字符串的起点的最大值和最小值,在判断最大值减最小值是否大于mid即可。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime> #define fuck(x) cerr<<#x<<" = "<<x<<endl;
#define debug(a, x) cerr<<#a<<"["<<x<<"] = "<<a[x]<<endl;
#define ls (t<<1)
#define rs ((t<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = ;
const int maxm = ;
const int inf = 0x3f3f3f3f;
const ll Inf = ;
const int mod = ;
const double eps = 1e-;
const double pi = acos(-); int s[maxn];
int len, Rank[maxn], sa[maxn], tlen, tmp[maxn]; bool compare_sa(int i, int j) {
if (Rank[i] != Rank[j]) { return Rank[i] < Rank[j]; }
//如果以i开始,长度为k的字符串的长度,已经超出了字符串尾,那么就赋值为-1
//这是因为,在前面所有数据相同的情况下,字符串短的字典序小.
int ri = i + tlen <= len ? Rank[i + tlen] : -inf;
int rj = j + tlen <= len ? Rank[j + tlen] : -inf;
return ri < rj;
} void construct_sa() {
//初始的RANK为字符的ASCII码
for (int i = ; i <= len; i++) {
sa[i] = i;
Rank[i] = i < len ? s[i] : -inf;
}
for (tlen = ; tlen <= len; tlen *= ) {
sort(sa, sa + len + , compare_sa);
tmp[sa[]] = ;
//全新版本的RANK,tmp用来计算新的rank
//将字典序最小的后缀rank计为0
//sa之中表示的后缀都是有序的,所以将下一个后缀与前一个后缀比较,如果大于前一个后缀,rank就比前一个加一.
//否则就和前一个相等.
for (int i = ; i <= len; i++) {
tmp[sa[i]] = tmp[sa[i - ]] + (compare_sa(sa[i - ], sa[i]) ? : );
}
for (int i = ; i <= len; i++) {
Rank[i] = tmp[i]; }
}
} int height[maxn]; void construct_lcp() {
// for(int i=0;i<=n;i++){Rank[sa[i]]=i;}
int h = ;
height[] = ;
for (int i = ; i < len; i++) {//i为后缀数组起始位置
int j = sa[Rank[i] - ];//获取当前后缀的前一个后缀(排序后)
if (h > )h--;
for (; j + h < len && i + h < len; h++) {
if (s[j + h] != s[i + h])break;
}
height[Rank[i]] = h;
}
} int st[maxn][]; void rmq_init() {
for (int i = ; i <= len; i++) {
st[i][] = height[i];
}
int l = ;
for (int i = ; l <= len; i++) {
for (int j = ; j + l / <= len; j++) {
st[j][i] = min(st[j][i - ], st[j + l / ][i - ]);
}
l <<= ;
}
} int ask_min(int i, int j) {
int k = int(log(j - i + 1.0) / log(2.0));
return min(st[i][k], st[j - ( << k) + ][k]);
} int lcp(int a, int b)//此处参数是,原字符串下标
{
a = Rank[a], b = Rank[b];
if (a > b)
swap(a, b);
return ask_min(a + , b);
} char str[maxn];
int intr[maxn];
int mx[];
int mn[];
int n;
bool check(int mid){
if(mid==){ return true;}
memset(mx,,sizeof(mn));
memset(mn,0x3f,sizeof(mn));
for(int i=;i<=len;i++){
int prestart = lower_bound(intr+,intr++n,sa[i-])-intr;
int start = lower_bound(intr+,intr++n,sa[i])-intr;
// cout<<height[i]<<endl;
if(height[i]>=mid){
mn[start]=min(mn[start],sa[i]);
mx[start]=max(mx[start],sa[i]);
mn[prestart]=min(mn[prestart],sa[i-]);
mx[prestart]=max(mx[prestart],sa[i-]);
}else{
bool flag=true;
// fuck(n)
for(int j=;j<=n;j++){
// cerr<<mx[j]<<" "<<mn[j]<<endl;
if(mx[j]-mn[j]<mid){flag=false;}
}
if(flag){return true;}
memset(mx,,sizeof(mn));
memset(mn,0x3f,sizeof(mn));
}
}
return false;
} int main() {
// ios::sync_with_stdio(false);
// freopen("in.txt", "r", stdin); int cases=; int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
cases++;
len=;
int lenx = ;
for(int i=;i<=n;i++){
scanf("%s",str);
int l=strlen(str);
lenx = max(lenx,l);
for(int j=;j<l;j++){
s[len++]=(int)str[j]-'a'+;
}
s[len++]=+i;
intr[i]=len-;
} construct_sa();
construct_lcp(); // fuck(check(4));
int l=,r=lenx;
int ans=;
while (r>=l){
int mid=(l+r)/;
// cout<<mid<<endl;
// cout<<l<<" "<<r<<endl;
if(check(mid)){
ans=mid;
l=mid+;
}else{
r=mid-;
}
}
printf("%d\n",ans);
} return ;
}
SPOJ - PHRASES Relevant Phrases of Annihilation (后缀数组)的更多相关文章
- SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串
题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags You ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组)
You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...
- SPOJ PHRASES Relevant Phrases of Annihilation(后缀数组 + 二分)题解
题意: 给\(n\)个串,要你求出一个最长子串\(A\),\(A\)在每个字串至少都出现\(2\)次且不覆盖,问\(A\)最长长度是多少 思路: 后缀数组处理完之后,二分这个长度,可以\(O(n)\) ...
- SPOJ220 Relevant Phrases of Annihilation(后缀数组)
引用罗穗骞论文中的话: 先将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,再将后缀分组.判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并 ...
- SPOJ - PHRASES Relevant Phrases of Annihilation
传送门:SPOJ - PHRASES(后缀数组+二分) 题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次. 题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡( ...
- 【SPOJ 220】 PHRASES - Relevant Phrases of Annihilation
[链接]h在这里写链接 [题意] 给你n(n<=10)个字符串. 每个字符串长度最大为1e4; 问你能不能找到一个子串. 使得这个子串,在每个字符串里面都不想交出 ...
- SPOJ 694 Distinct Substrings/SPOJ 705 New Distinct Substrings(后缀数组)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- SPOJ SUBST1 New Distinct Substrings(后缀数组 本质不同子串个数)题解
题意: 问给定串有多少本质不同的子串? 思路: 子串必是某一后缀的前缀,假如是某一后缀\(sa[k]\),那么会有\(n - sa[k] + 1\)个前缀,但是其中有\(height[k]\)个和上一 ...
随机推荐
- bzoj3522 Hotel
Description 有一个树形结构的宾馆,n个房间,n-1条无向边,每条边的长度相同,任意两个房间可以相互到达.吉丽要给他的三个妹子各开(一个)房(间).三个妹子住的房间要互不相同(否则要打起来了 ...
- 基于Spark Mllib的Spark NLP库
SparkNLP的官方文档 1>sbt引入: scala为2.11时 libraryDependencies += "com.johnsnowlabs.nlp" %% &qu ...
- 块级元素及内联元素对margin、padding的态度
1.块级元素 margin:跟标准一样,设置该块级元素边框与同级兄弟元素或者父元素的距离,俗称外边距. padding:先延伸边框(也就是优先改变元素尺寸而不动元素中内容的位置),当边框碰到父元素的边 ...
- c++第四次作业:继承
继承与派生 基本概念和语法 概念 继承与派生是同一过程从不同角度看 保持已有的特性而构造新类的过程称为继承. 在已有类的基础上新增自己的特性而产生新类的过程为派生. 被继承的已有类称为基类(父类) 派 ...
- 04使用harbor配置私仓
安装harbor之前,需要安装好Python,Docker,DockerCompose.Python需要2.7以上的版本,Docker需要1.10以上的版本:Docker Compose 需要1.6. ...
- Jmeter xpath处理器
- Oracle基础学习4--Oracle权限传递
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/wang379275614/article/details/32215325 以下将用一个实例来解说: ...
- Laravel5.1 实现第三方登录认证教程之 - 微信登录
https://laravel-china.org/topics/2451/laravel51-implementation-of-the-third-party-login-authenticati ...
- 1878: [SDOI2009]HH的项 莫队算法-离线查询区间内部不同数字的个数
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...
- Java模板引擎FreeMarker介绍和使用
http://blog.csdn.net/shimiso/article/details/8778793