题面
解析
先奉上YYR的PPT
基本思路这张PPT已经讲清楚了,但还有一些其他的细节
我们确定了$L*t$与$L*(t+1)$后,显然不能暴力向后跳或向前跳。考虑向后跳最多跳$LCP(L*t, L*(t+1))$个点,因此这个可以用后缀数组+RMQ预处理出来,快速查询。再考虑向前跳,向前跳最多产生1个循环节,因为如果有多个循环节的话,必定存在一个更小的t使得向前跳跳到相同起点,并且最多产生一个循环节,那么什么时候会产生一个循环节呢?
令$len = LCP(L*t, L*(t+1))$, 此时循环节个数为$res = len / L + 1$, 超出循环节的部分为$k' = len % L$,显然如果能向前跳至少$k = L - k'$个点,就可以产生1个循环节,即满足$LCP(L*t-k, L*t-k+L) geqslant L$时,$ res++$
代码:

#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn = 50004; int T, n, ans; int sa[maxn], rk[maxn], fir[maxn], sec[maxn], c[maxn], hei[maxn]; char s[maxn]; void Build_SA() { int m = 26; for(int i = 1; i <= n; ++i) fir[i] = s[i] - 'a' + 1; for(int i = 0; i <= m; ++i) c[i] = 0; for(int i = 1; i <= n; ++i) c[fir[i]] ++; for(int i = 1; i <= m; ++i) c[i] += c[i-1]; for(int i = n; i; --i) sa[c[fir[i]]--] = i; for(int k = 1; k <= n; k <<= 1) { int t = 0; for(int i = n - k + 1; i <= n; ++i) sec[++t] = i; for(int i = 1; i <= n; ++i) if(sa[i] > k) sec[++t] = sa[i] - k; for(int i = 0; i <= m; ++i) c[i] = 0; for(int i = 1; i <= n; ++i) c[fir[sec[i]]] ++; for(int i = 1; i <= m; ++i) c[i] += c[i-1]; for(int i = n; i; --i) sa[c[fir[sec[i]]]--] = sec[i], sec[i] = 0; for(int i = 1; i <= n; ++i) swap(fir[i], sec[i]); t = 0; fir[sa[1]] = ++t; for(int i = 2; i <= n; ++i) if(sec[sa[i]] != sec[sa[i-1]] || sec[sa[i]+k] != sec[sa[i-1]+k]) fir[sa[i]] = ++t; else fir[sa[i]] = t; if(t >= n) break; m = t; } for(int i = 1; i <= n; ++i) fir[i] = sec[i] = 0; } void Get_hei() { int h = 0; for(int i = 1; i <= n; ++i) rk[sa[i]] = i; for(int i = 1; i <= n; ++i) { int t = sa[rk[i]-1]; while(s[t+h] == s[i+h]) h++; hei[rk[i]] = h; h = max(0, h - 1); } } int lg[maxn], mn[20][maxn]; void RMQ() { for(int i = 1; i <= n; ++i) mn[0][i] = hei[i]; for(int j = 1; j <= lg[n]; ++j) for(int i = 1; i + (1<<j) - 1 <= n; ++i) mn[j][i] = min(mn[j-1][i], mn[j-1][i+(1<<(j-1))]); } int query(int x, int y) { if(x > y) swap(x, y); return min(mn[lg[y-x]][x+1], mn[lg[y-x]][y-(1<<lg[y-x])+1]); } int main() { lg[0] = -1; for(int i = 1; i <= 50000; ++i) lg[i] = lg[i>>1] + 1; scanf("%d", &T); while(T--) { scanf("%d", &n); char c[5]; for(int i = 1; i <= n; ++i) { scanf("%s", c); s[i] = c[0]; } s[n+1] = 0; Build_SA(); Get_hei(); RMQ(); ans = 1; for(int i = 1; i <= n; ++i) for(int j = 1; j + i <= n; j += i) { int l = query(rk[j], rk[j+i]); int res = l / i + 1, k = i - l % i; if(j - k && query(rk[j-k], rk[j-k+i]) >= i) res++; ans = max(ans, res); j += l / i * i; } printf("%d ", ans); } return 0; }