Description
You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.
Input
The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.
Output
There should be one line per test case containing the length of the largest string found.
Sample Input
2
3
ABCD
BCDFF
BRCD
2
rose
orchid
Sample Output
2
2
后缀数组+二分
#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define fi first
#define se second
#define mp(i,j) make_pair(i,j)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int read()
{
char ch = getchar();
while (ch<'0' || ch>'9') ch = getchar();
int x = ch - '0';
while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
return x;
}
int T, m;
struct Sa
{
char c[N];
int s[N];
int rk[2][N], sa[N], h[N], w[N], now, n;
int rmq[N][20], lg[N], bel[N];
bool GetS()
{
scanf("%d", &m);
n = 0;
int q = 200;
rep(i, 1, m)
{
scanf("%s", c + 1);
for (int j = 1; c[j]; j++)
{
bel[++n] = i - 1; s[n] = c[j];
}
s[++n] = q++; bel[n] = 100;
for (int j = strlen(c + 1); j; j--)
{
bel[++n] = i - 1; s[n] = c[j];
}
s[++n] = q++; bel[n] = 100;
}
--n;
return true;
}
void getsa(int z, int &m)
{
int x = now, y = now ^= 1;
rep(i, 1, z) rk[y][i] = n - i + 1;
for (int i = 1, j = z; i <= n; i++)
if (sa[i] > z) rk[y][++j] = sa[i] - z;
rep(i, 1, m) w[i] = 0;
rep(i, 1, n) w[rk[x][rk[y][i]]]++;
rep(i, 1, m) w[i] += w[i - 1];
per(i, n, 1) sa[w[rk[x][rk[y][i]]]--] = rk[y][i];
for (int i = m = 1; i <= n; i++)
{
int *a = rk[x] + sa[i], *b = rk[x] + sa[i - 1];
rk[y][sa[i]] = *a == *b&&*(a + z) == *(b + z) ? m - 1 : m++;
}
}
void getsa(int m)
{
//n = strlen(s + 1);
rk[1][0] = now = sa[0] = s[0] = 0;
rep(i, 1, m) w[i] = 0;
rep(i, 1, n) w[s[i]]++;
rep(i, 1, m) rk[1][i] = rk[1][i - 1] + (bool)w[i];
rep(i, 1, m) w[i] += w[i - 1];
rep(i, 1, n) rk[0][i] = rk[1][s[i]];
rep(i, 1, n) sa[w[s[i]]--] = i;
rk[1][n + 1] = rk[0][n + 1] = 0; //多组的时候容易出bug
for (int x = 1, y = rk[1][m]; x <= n && y <= n; x <<= 1) getsa(x, y);
for (int i = 1, j = 0; i <= n; h[rk[now][i++]] = j ? j-- : j)
{
if (rk[now][i] == 1) continue;
int k = n - max(sa[rk[now][i] - 1], i);
while (j <= k && s[sa[rk[now][i] - 1] + j] == s[i + j]) ++j;
}
}
void getrmq()
{
h[n + 1] = h[1] = lg[1] = 0;
rep(i, 2, n) rmq[i][0] = h[i], lg[i] = lg[i >> 1] + 1;
for (int i = 1; (1 << i) <= n; i++)
{
rep(j, 2, n)
{
if (j + (1 << i) > n + 1) break;
rmq[j][i] = min(rmq[j][i - 1], rmq[j + (1 << i - 1)][i - 1]);
}
}
}
int lcp(int x, int y)
{
int l = min(rk[now][x], rk[now][y]) + 1, r = max(rk[now][x], rk[now][y]);
return min(rmq[l][lg[r - l + 1]], rmq[r - (1 << lg[r - l + 1]) + 1][lg[r - l + 1]]);
}
bool check(int x)
{
bitset<101> f;
rep(i, 2, n)
{
if (h[i] >= x) f[bel[sa[i]]] = f[bel[sa[i - 1]]] = 1;
else
{
f[100] = 0;
if (f.count() == m) return true; else f.reset();
}
}
f[100] = 0;
return f.count() == m;
}
void work()
{
GetS(); getsa(400);
if (m == 1) { printf("%d\n", n / 2); return; }
int l = 1, r = n;
while (l <= r)
{
if (check(l + r >> 1)) l = (l + r >> 1) + 1;
else r = (l + r >> 1) - 1;
}
printf("%d\n", r);
}
}sa;
int main()
{
T = read();
while (T--) sa.work();
return 0;
}