大意:多组数据,每组n个字符串,寻找最长的X,使得对n个字符串中的任意一个,X或者X反转过来的字符串
是其子串。(输出X的长度即可)
思路:这道好像KMP或者后缀数组都能做,但我还是习惯用哈希。此题可以先二分这个长度(显然如果某个长度满足
那么小于这个长度的串也是能找到的),不妨记这个长度为len。然后呢,以第一个字符串为标准,正一遍反一遍扫过去得到该字符串中,以i为下标开始的长度为len的子串的哈希值(不妨记为h1[i]),以及其翻转过来串对应的哈希值(不妨记为h2[i])。同时,后面几个字符串中长度为len的子串的哈希值也可处理出来,放到容器里。接下来,就是
看是否存在这样的i,使得剩余n-1个字符串对应的n-1个容器里要么含有h1[i],要么含有h2[i]。如果是则len可以,所求长度肯定大于等于len;否则,所求长度小于len。
代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.StringTokenizer;
class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
static void init(InputStream input) {
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}
static String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
public class Main {
/**
* @param args
*/
static int t, n, cnt, len1;
static char ch[][];
static int hash1[], hashin[];
static HashSet<Integer> hashSet[];
static String str;
static long mul = 100000007;
static long monum = Integer.MAX_VALUE;
static long mulnum;
private static boolean isOk(int num) {
hashSet = new HashSet[n + 1];
for (int i = 1; i <= n; i++)
hashSet[i] = new HashSet<Integer>();
mulnum = 1;
for (int i = 1; i <= num; i++)
mulnum = (mulnum * mul) % monum;
long v;
for (int i = 2; i <= n; i++) {
if (ch[i].length < num)
return false;
v = 0;
for (int j = 0; j < num; j++)
v = (v * mul + (long) ch[i][j]) % monum;
hashSet[i].add((int) v);
for (int j = num; j < ch[i].length; j++) {
v = (v * mul + (long) ch[i][j]) % monum;
v = ((v - mulnum * (long) ch[i][j - num]) % monum + monum)
% monum;
hashSet[i].add((int) v);
}
}
hash1 = new int[len1 + 1];
hashin = new int[len1 + 1];
v = 0;
for (int i = 0; i < num; i++) {
v = (v * mul + (long) ch[1][i]) % monum;
}
hash1[1] = (int) v;
for (int i = num; i < len1; i++) {
v = (v * mul + (long) ch[1][i]) % monum;
v = ((v - mulnum * (long) ch[1][i - num]) % monum + monum) % monum;
hash1[i - num + 2] = (int) v;
}
v = 0;
for (int i = len1 - 1; i >= len1 - num; i--) {
v = (v * mul + (long) ch[1][i]) % monum;
}
hashin[len1 - num + 1] = (int) v;
for (int i = len1 - num - 1; i >= 0; i--) {
v = (v * mul + (long) ch[1][i]) % monum;
v = ((v - mulnum * (long) ch[1][i + num]) % monum + monum) % monum;
hashin[i + 1] = (int) v;
}
boolean flag;
for (int i = 1; i <= len1; i++) {
flag = true;
for (int j = 2; j <= n; j++)
if ((!hashSet[j].contains(hash1[i]))
&& (!hashSet[j].contains(hashin[i]))) {
flag = false;
break;
}
if (flag)
return true;
}
return false;
}
private static void deal() {
len1 = ch[1].length;
int l = 0;
int r = ch[1].length;
if (n == 1) {
System.out.println(r);
return;
}
int mid;
while (r - l > 1) {
mid = (l + r) / 2;
if (isOk(mid))
l = mid;
else
r = mid;
}
if (isOk(r))
System.out.println(r);
else
System.out.println((r - 1));
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Reader.init(System.in);
t = Reader.nextInt();
ch = new char[101][];
for (int casenum = 1; casenum <= t; casenum++) {
n = Reader.nextInt();
for (int i = 1; i <= n; i++) {
str = Reader.next();
ch[i] = str.toCharArray();
}
deal();
}
}
}