【链接】h在这里写链接
【题意】
给你n个字符串。
让你找一个字符串s.
设s'为这个字符串的逆序。
要求s或者s'在每个字符串里都能够找得到.
并且要求s的长度最长。
求出这个最长的串的长度.
让你找一个字符串s.
设s'为这个字符串的逆序。
要求s或者s'在每个字符串里都能够找得到.
并且要求s的长度最长。
求出这个最长的串的长度.
【题解】
把n个串,每个串逆序或者是倒序.顺序加成一个串.
(标记一下每个串是属于第几个串..逆序顺序属于同一个串!)
(中间用没有出现过的连字符连在一起)
(连字符大概有100*2个)
200+300;
//每个字符串的最大值设成500就好
然后求出其后缀数组
最大长度100*2*100=20000 + 200;
然后,二分一下要找的串的长度length.
然后,按照Height值分一下组。
->连续大于等于length的。
然后看看这些后缀的起点,是不是包括了所有的字符串就可以了
->方便一点就用set判重就好
如果包含了所有的字符串的话,那么就返回true;
(标记一下每个串是属于第几个串..逆序顺序属于同一个串!)
(中间用没有出现过的连字符连在一起)
(连字符大概有100*2个)
200+300;
//每个字符串的最大值设成500就好
然后求出其后缀数组
最大长度100*2*100=20000 + 200;
然后,二分一下要找的串的长度length.
然后,按照Height值分一下组。
->连续大于等于length的。
然后看看这些后缀的起点,是不是包括了所有的字符串就可以了
->方便一点就用set判重就好
如果包含了所有的字符串的话,那么就返回true;
【错的次数】
0
【反思】
二分如果为0的不能满足->那么就可能不能到达1的;
【代码】
#include <cstdio> #include <string> #include <algorithm> #include <iostream> #include <set> using namespace std; const int N = 3e4; const int NN = 100; const int MAX_CHAR = 1000;//每个数字的最大值。 int s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存 int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10]; int Height[N + 10], Rank[N + 10], idx[N + 10]; int n, len; void build_Sa(int n, int m) { int i, *x = T1, *y = T2; for (i = 0; i<m; i++) C[i] = 0; for (i = 0; i<n; i++) C[x[i] = s[i]]++; for (i = 1; i<m; i++) C[i] += C[i - 1]; for (i = n - 1; i >= 0; i--) Sa[--C[x[i]]] = i; for (int k = 1; k <= n; k <<= 1) { int p = 0; for (i = n - k; i<n; i++) y[p++] = i; for (i = 0; i<n; i++) if (Sa[i] >= k) y[p++] = Sa[i] - k; for (i = 0; i<m; i++) C[i] = 0; for (i = 0; i<n; i++) C[x[y[i]]]++; for (i = 1; i<m; i++) C[i] += C[i - 1]; for (i = n - 1; i >= 0; i--) Sa[--C[x[y[i]]]] = y[i]; swap(x, y); p = 1; x[Sa[0]] = 0; for (i = 1; i<n; i++) x[Sa[i]] = y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + k] == y[Sa[i] + k] ? p - 1 : p++; if (p >= n) break; m = p; } } void getHeight(int n) { int i, j, k = 0; for (i = 1; i <= n; i++) Rank[Sa[i]] = i; for (i = 0; i<n; i++) { if (k) k--; j = Sa[Rank[i] - 1]; while (s[i + k] == s[j + k]) k++; Height[Rank[i]] = k; } } bool ok(int l) { set <int> mset; mset.clear(); for (int i = 2; i <= len; i++) if (Height[i] >= l) { mset.insert(idx[Sa[i - 1]]); mset.insert(idx[Sa[i]]); } else { if ((int)mset.size() == n) return true; mset.clear(); } if ((int)mset.size() == n) return true; return false; } int main() { //freopen("F:\rush.txt", "r", stdin); int T; cin >> T; while (T--) { int special = -1; len = 0; int spe = 'z' + 1; cin >> n; for (int i = 1; i <= n; i++) { string S; cin >> S; int ls = S.size(); if (n == 1) special = ls; for (int j = 0; j < ls; j++) { idx[len] = i; s[len++] = S[j]; } s[len++] = spe++; reverse(S.begin(), S.end()); for (int j = 0; j < ls; j++) { idx[len] = i; s[len++] = S[j]; } s[len++] = spe++; } if (special != -1) { cout << special << endl; continue; } s[len] = 0; build_Sa(len + 1, MAX_CHAR); getHeight(len); //开始写二分部分 int l = 1, r = 100, temp = 0;//如果l的初始值为0的话,ok函数最后那行集合大小为n的判断就不能 //省掉,因为所有函数的Height值都为0的>_<,集合大小为n的判断就漏掉了 while (l <= r) { int mid = (l + r) >> 1; if (ok(mid)) { temp = mid; l = mid + 1; } else r = mid - 1; } cout << temp << endl; } return 0; }