P3426 [POI2005]SZA-Template
分析:
首先T一定是S的一个前缀,也是一个后缀。
判断一个前缀s[1...i]是不是满足条件,那么求出s[1...i]在s中出现的所有位置,如果相邻的两个位置之间的距离的最大值小于等于i,那么就是满足的。
于是可以建出fail树,每次从根到n走,那么出现的位置的个数是递减的,于是链表维护即可。
代码:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #include<bitset> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 1000005; int p[N], L[N], R[N], to[N], mx; vector<int> T[N]; char s[N]; void del(int x) { if (x) { int a = L[x], b = R[x]; mx = max(mx, b - a); L[b] = a, R[a] = b; } for (auto v : T[x]) if (v != to[x]) del(v); } int main() { scanf("%s", s + 1); int n = strlen(s + 1); p[1] = 0; for (int j = 0, i = 2; i <= n; ++i) { while (j && s[j + 1] != s[i]) j = p[j]; if (s[j + 1] == s[i]) j ++; p[i] = j; } for (int i = 1; i <= n; ++i) T[p[i]].push_back(i); for (int i = n; i; i = p[i]) to[p[i]] = i; for (int i = 1; i <= n; ++i) L[i] = i - 1, R[i] = i + 1; int now = 1; del(0); while (now < mx) { del(now), now = to[now]; } cout << now; return 0; }
’