大意:多组数据,每组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(); } } }