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.

题目大意:给n个字符串,求在每个字符串中出现至少两次且不重叠的最长子串的长度。

思路:每个字符串用不相同的字符连起来。求后缀数组和height[]数组。

二分长度L,检查长度。

检查的时候从前往后扫一遍,看有没有连起来的一部分,公共前缀大于等于L且在每个字符串中都出现了且不重叠。

复杂度为O(nlogn)

代码(0.34s):

 #include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; const int MAXN = ; char s[MAXN];
int id[MAXN];
int sa[MAXN], rank[MAXN], height[MAXN], c[MAXN], tmp[MAXN];
int n, m, T; void makesa(int m) {
memset(c, , m * sizeof(int));
for(int i = ; i < n; ++i) ++c[rank[i] = s[i]];
for(int i = ; i < m; ++i) c[i] += c[i - ];
for(int i = ; i < n; ++i) sa[--c[rank[i]]] = i;
for(int k = ; k < n; k <<= ) {
for(int i = ; i < n; ++i) {
int j = sa[i] - k;
if(j < ) j += n;
tmp[c[rank[j]]++] = j;
}
int j = c[] = sa[tmp[]] = ;
for(int i = ; i < n; ++i) {
if(rank[tmp[i]] != rank[tmp[i - ]] || rank[tmp[i] + k] != rank[tmp[i - ] + k])
c[++j] = i;
sa[tmp[i]] = j;
}
memcpy(rank, sa, n * sizeof(int));
memcpy(sa, tmp, n * sizeof(int));
}
} void calheight() {
for(int i = , k = ; i < n; height[rank[i++]] = k) {
k -= (k > );
int j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) ++k;
}
} int mx[MAXN], mn[MAXN];
int stk[MAXN]; void update_max(int &a, int b) {
if(a == - || a < b) a = b;
} void update_min(int &a, int b) {
if(a == - || a > b) a = b;
} bool check(int L) {
int sum = , top = ;
memset(mx, -, m * sizeof(int));
memset(mn, -, m * sizeof(int));
memset(c, , m * sizeof(int));
for(int i = ; i < n; ++i) {
if(height[i] >= L) {
update_max(mx[id[sa[i]]], sa[i]);
update_min(mn[id[sa[i]]], sa[i]);
stk[++top] = id[sa[i]];
if(mx[id[sa[i]]] - mn[id[sa[i]]] >= L) {
if(!c[id[sa[i]]]) ++sum;
c[id[sa[i]]] = true;
if(sum >= m) return true;
}
} else {
sum = ;
while(top) {
int t = stk[top--];
mx[t] = mn[t] = -;
c[t] = false;
}
update_max(mx[id[sa[i]]], sa[i]);
update_min(mn[id[sa[i]]], sa[i]);
stk[++top] = id[sa[i]];
}
}
return false;
} int solve() {
int l = , r = ;
while(l < r) {
int mid = (l + r) >> ;
if(check(mid)) l = mid + ;
else r = mid;
}
return l - ;
} int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &m);
n = ;
for(int i = ; i < m; ++i) {
scanf("%s", s + n);
while(s[n]) id[n++] = i;
s[n++] = i + ;
}
s[n - ] = ;
makesa();
calheight();
printf("%d\n", solve());
}
}

SPOJ 220 Relevant Phrases of Annihilation(后缀数组)的更多相关文章

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

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

  2. SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)

    [题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...

  3. SPOJ220 Relevant Phrases of Annihilation(后缀数组)

    引用罗穗骞论文中的话: 先将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,再将后缀分组.判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并 ...

  4. 【SPOJ 220】Relevant Phrases of Annihilation

    http://www.spoj.com/problems/PHRASES/ 求出后缀数组然后二分. 因为有多组数据,所以倍增求后缀数组时要特判是否越界. 二分答案时的判断要注意优化! 时间复杂度\(O ...

  5. POJ - 3294~Relevant Phrases of Annihilation SPOJ - PHRASES~Substrings POJ - 1226~POJ - 3450 ~ POJ - 3080 (后缀数组求解多个串的公共字串问题)

    多个字符串的相关问题 这类问题的一个常用做法是,先将所有的字符串连接起来, 然后求后缀数组 和 height 数组,再利用 height 数组进行求解. 这中间可能需要二分答案. POJ - 3294 ...

  6. SPOJ - PHRASES K - Relevant Phrases of Annihilation

    K - Relevant Phrases of Annihilation 题目大意:给你 n 个串,问你最长的在每个字符串中出现两次且不重叠的子串的长度. 思路:二分长度,然后将height分块,看是 ...

  7. SPOJ - PHRASES Relevant Phrases of Annihilation (后缀数组)

    You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...

  8. SPOJ PHRASES Relevant Phrases of Annihilation(后缀数组 + 二分)题解

    题意: 给\(n\)个串,要你求出一个最长子串\(A\),\(A\)在每个字串至少都出现\(2\)次且不覆盖,问\(A\)最长长度是多少 思路: 后缀数组处理完之后,二分这个长度,可以\(O(n)\) ...

  9. 【SPOJ 220】 PHRASES - Relevant Phrases of Annihilation

    [链接]h在这里写链接 [题意]     给你n(n<=10)个字符串.     每个字符串长度最大为1e4;     问你能不能找到一个子串.     使得这个子串,在每个字符串里面都不想交出 ...

随机推荐

  1. C++ 安全字符串拼接

    #include <stdio.h> #include <stdint.h> #include <stdarg.h> #if defined(__GNUC__) # ...

  2. 经典Bug 修改方法

    右击工程名,“显示包内容”,删除提示错误的所有相关内容,(想当初,仅仅是删了一个图片,就各种报错,clean也没用,删了重新运行,也不成功.....有能力的话,最好能FQ,google你会发现很多技巧 ...

  3. php保存远程文件到本地的方法

    用到了ob_start();<?php header("Content-type:text/html charset=utf-8"); if(!empty($_POST['p ...

  4. js - 驼峰命名

    1. // 驼峰命名 console.log(hump('border-bottom-color')) function hump( str) { if (typeof str != 'string' ...

  5. IN和exists 之间的比较

    IN和exists 之间的比较 NOT IN 和 NOT EXISTS之间的比较

  6. http://blog.csdn.net/rongyongfeikai2/article/details/41659353

    http://blog.csdn.net/rongyongfeikai2/article/details/41659353

  7. AppStore提审攻略

    导语: AppStore后台上传新产品的时候需要填写很多资料,看似很复杂,其实搞清楚之后也比较简单. 下面就给大家介绍一下  iTunes Connect 后台上传新APP时需要提交的资料.不要等待需 ...

  8. python笔记 - day7

    python笔记 - day7 参考: http://www.cnblogs.com/wupeiqi/articles/5501365.html 面向对象,初级篇: http://www.cnblog ...

  9. Number类型

    这是计算基础,复杂的以后不充. 1.Number(); var box = { toString :function(){ return '123'; } }; alert(Number(box)); ...

  10. delegate and event

    事件是特殊的委托 委托:第一个方法注册用“=”,是赋值语法,因为要进行实例化,第二个方法注册则用的是“+=”   修饰符应该public的时候public,应该private的时候private 事件 ...