5 xy abc aaa aaaaba aaxoaaaaa
0 0 1 1 2
题意其实就是要找到这个字符串的某个前缀, 它在串中至少出现了三次(末尾1次,中间一次, 开头一次)
那么我们可以用EKMP,先把next数组预处理出来(串和串本身的每一个后缀的最长公共前缀), 然后用树状数组维护大于等于next[i]的值的个数
显然符合的次数肯定大于等于3, 然后只要从后往前去找那些 i + next[i] == len 的 后缀(只有匹配到结束才说明存在某个前缀出现在后缀里),找一个最大值就行
复杂度O(nlogn)
/************************************************************************* > File Name: hdu4763.cpp > Author: ALex > Mail: [email protected] > Created Time: 2015年02月02日 星期一 13时11分11秒 ************************************************************************/ #include <map> #include <set> #include <queue> #include <stack> #include <vector> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const double eps = 1e-15; typedef long long LL; typedef pair <int, int> PLL; const int N = 1000100; char T[N]; int next[N]; int cnt_hash[N]; int tree[N]; int lowbit (int x) { return x & (-x); } void add (int x) { for (int i = x; i <= N; i += lowbit(i)) { ++tree[i]; } } int sum (int x) { int ans = 0; for (int i = x; i; i -= lowbit (i)) { ans += tree[i]; } return ans; } void EKMP () { int lent = strlen (T); next[0] = lent; int i, j, p, L; j = 0; while (j + 1 < lent && T[j] == T[j + 1]) { ++j; } next[1] = j; int a = 1; for (int i = 2; i < lent; ++i) { p = next[a] + a - 1; L = next[i - a]; if (i + L < p + 1) { next[i] = L; } else { j = max (0, p - i + 1); while (i + j < lent && T[i + j] == T[j]) { ++j; } next[i] = j; a = i; } } } int main () { int t; scanf("%d", &t); while (t--) { memset (next, 0, sizeof(next)); memset (tree, 0, sizeof(tree)); scanf("%s", T); EKMP (); int len = strlen (T); int maxs = 0; int zero = 0; for (int i = 0; i < len; ++i) { if (next[i] == 0) { ++zero; continue; } add (next[i]); } for (int i = len - 1; i >= 0; --i) { if (next[i] == 0) { continue; } if (i + next[i] - 1 != len - 1) { continue; } int cnt = len - sum (next[i] - 1) - zero; if (cnt >= 3) { maxs = max (maxs, next[i]); } } printf("%d\n", maxs); } return 0; }