Description

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
/*
SPOJ PHRASES 每个字符串至少出现两次且不重叠的最长子串 因为是求的最长子串,所以考虑二分长度len
然后我们需要对其进行判断,对于每一个连续大于等于len的height[](分组讨论)
记录各个串中的情况,因为要判断不是重叠的,所以对于每个串,我们记录
它满足height>=len的最大最小位置
如果所有串的max-min >= len 则说明存在长度为len的子串在
每个串都有出现两次且不重叠 感觉思路没什么问题,主要是最开始代码写得不够简洁,而且WR hhh-2016-03-21 23:01:01
*/
#include <algorithm>
#include <cmath>
#include <queue>
#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
#include <vector>
#include <functional>
#define lson (i<<1)
#define rson ((i<<1)|1)
using namespace std;
typedef long long ll;
const int maxn = 101000; int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *r,int a,int b,int l)
{
return r[a]==r[b] &&r[l+a] == r[l+b];
} void get_sa(int str[],int sa[],int Rank[],int height[],int n,int m)
{
n++;
int p,*x=t1,*y=t2;
for(int i = 0; i < m; i++) c[i] = 0;
for(int i = 0; i < n; i++) c[x[i] = str[i]]++;
for(int i = 1; i < m; i++) c[i] += c[i-1];
for(int i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
for(int j = 1; j <= n; j <<= 1)
{
p = 0;
for(int i = n-j; i < n; i++) y[p++] = i;
for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
for(int i = 0; i < m; i++) c[i] = 0;
for(int i = 0; i < n; i++) c[x[y[i]]]++ ;
for(int i = 1; i < m; i++) c[i] += c[i-1];
for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y);
p = 1;
x[sa[0]] = 0;
for(int i = 1; i < n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],j)? p-1:p++;
if(p >= n) break;
m = p;
}
int k = 0;
n--;
for(int i = 0; i <= n; i++)
Rank[sa[i]] = i;
for(int i = 0; i < n; i++)
{
if(k) k--;
int j = sa[Rank[i]-1];
while(str[i+k] == str[j+k]) k++;
height[Rank[i]] = k;
}
} int Rank[maxn];
int sa[maxn];
int str[maxn],height[maxn];
char s[maxn];
int id[maxn];
struct node
{
int Min;
int Max;
int flag;
} anspos[15]; void ini()
{
for(int i = 0; i <= 12; i++)
anspos[i].Min = 0x3f3f3f3f,anspos[i].Max = -1;
} bool can(int len,int n,int num)
{
int l = 2,r = 2;
ini();
for(int i = 2; i <= n; i++)
{
if(height[i] >= len)
{
int id1=id[sa[i-1]];
int id2=id[sa[i]]; anspos[id1].Max=max(anspos[id1].Max,sa[i-1]);
anspos[id1].Min=min(anspos[id1].Min,sa[i-1]); anspos[id2].Max=max(anspos[id2].Max,sa[i]);
anspos[id2].Min=min(anspos[id2].Min,sa[i]);
int t;
for(t = 0; t < num; t++)
if(anspos[t].Max - anspos[t].Min < len)
break;
if(t == num)
return 1;
}
else
{
for(int j = 0; j <= 10; j++)
anspos[j].Min = 0x3f3f3f3f,anspos[j].Max = -1;
}
}
for(int i = 0; i < num; i++)
if(!anspos[i].flag)
return 0;
return 1;
} int main()
{
int k,n,t;
scanf("%d",&t);
while(t--)
{
ini();
int tot = 0,len = 0x3f3f3f3f;
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%s",s);
for(int j = 0; s[j]!='\0'; j++)
{
id[tot] = i;
str[tot++] = s[j]-'a'+10;
}
id[tot] = i;
str[tot++] = i;
len = min(len,(int)strlen(s));
}
str[tot] = 0;
get_sa(str,sa,Rank,height,tot,100);
int l = 0,r = len;
int ans = 0;
while(l <= r)
{
int mid = (l+r)>>1;
if(can(mid,tot,n))
{
ans = mid;
l = mid+1;
}
else
r = mid-1;
}
printf("%d\n",ans);
}
return 0;
}

  

SPOJ PHRASES 每个字符串至少出现两次且不重叠的最长子串的更多相关文章

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

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

  2. hdoj 3746 Cyclic Nacklace【KMP求在结尾加上多少个字符可以使字符串至少有两次循环】

    Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

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

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

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

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

  5. SPOJ - PHRASES K - Relevant Phrases of Annihilation

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

  6. SPOJ PHRASES 后缀数组

    题目链接:http://www.spoj.com/problems/PHRASES/en/ 题意:给定n个字符串,求一个最长的子串至少在每个串中的不重叠出现次数都不小于2.输出满足条件的最长子串长度 ...

  7. SPOJ - PHRASES Relevant Phrases of Annihilation

    传送门:SPOJ - PHRASES(后缀数组+二分) 题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次. 题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡( ...

  8. 华为 1.static有什么用途?(请至少说明两种)

    1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问 ...

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

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

随机推荐

  1. 2017-2018-1 我爱学Java 第八周 作业

    团队六七周作业 团队分工 UML图 工具选择 小编(金立清)有话说 参考资料 团队分工 返回目录 UML图 用例图 类图 活动图 状态图 返回目录 工具选择 ProcessOn - 免费在线作图,实时 ...

  2. CPP链表示例

    #include<iostream> #include<stdlib.h> using namespace std; typedef struct Student_data { ...

  3. Android实验报告

    实验名称:Android程序设计 实验时间:2017.5.24 实验人员:20162309邢天岳(结对同学20162313苑洪铭) 实验目的:使用android stuidio开发工具进行基本安卓软件 ...

  4. mongodb监控工具mongostat

    mongostat的使用及命令详解 mongostat是mongodb自带的状态检测工具,在命令行下使用,会间隔固定时间获取mongodb的当前运行状态,并输出. 1.常用命令格式: mongosta ...

  5. ajax和jquery使用技巧

    1.使用ajax的方法的时候可以使用u方法来获取连接,这样更加安全:alert弹窗的时候需要单引号双引号火狐浏览器会报错!

  6. 【漏洞复现】PHPCMS wap模块 SQL注入(附EXP)

    漏洞影响版本:v9.5.8.v9.6.0 Step1: 访问:http://www.xxx.com/index.php?m=wap&a=index&siteid=1, 获取返回的coo ...

  7. 原生Ajax用法——一个简单的实例

    Ajax全名(Asynchronous(异步) JavaScript and XML )是可以实现局部刷新的 在讲AJax之前我们先用简单的实例说一下同步和异步这个概念 /*异步的概念(就是当领导有一 ...

  8. Python之socketserver模块和验证客户端链接的合法性

    验证客户端链接的合法性 分布式系统中实现一个简单的客户端链接认证功能 #_*_coding:utf-8_*_ from socket import * import hmac,os secret_ke ...

  9. find文件查找

    一.locate locate基于数据库索引来查找文件,数据库在开机时一段时间对更新,不会实时更新,数据库存放在(/var/lib/mlocate/mlocate.db),可以用updatedb来手动 ...

  10. Java-Maven(八):IDEA使用本地maven,并配置远程中央仓库

    声明:已经安装了maven,安装请参考:<Java-Maven(一):Maven的简介与安装> 1)一般我们从github.码云(https://gitee.com)上获取代码后,实际上我 ...