题目大意:求出一个字符串$S$每一位的$num[i]$,最多$5$组询问,$|S|\leqslant10^6$
$num[i]$定义为$S_{1,i}$中长度不超过$\lfloor\dfrac i2\rfloor$的$border$的个数
题解:类似$KMP$。发现一个字符串$border$的$border$一定是原串的$border$,并且若每次是最长$border$的话,所有的$border$均会被枚举到。令$res[i]$表示$S_{1,i}$的$border$个数$+1$(即包括$S_{1,i}$),则若$S_{1,i}$为$S_{1,j}$的一个$border$且$i$为所有满足$i\leqslant\lfloor\dfrac j2\rfloor$中最大的,则$num[j]=res[i]$。$res$数组可以在求$nxt$数组时顺带求出。现在就是要对于$j$快速求出$i$。可以通过类似$KMP$的方法,求出了$j$对应的$i$,在就$j+1$时,就直接对$i$进行修改,若$i>\lfloor\dfrac j2\rfloor$,重复$i=nxt[i]$直到满足条件。这样复杂度和$KMP$一样是$O(n)$的
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> const int maxn = 1e6 + 10, mod = 1e9 + 7; int Tim, n, ans; char s[maxn]; int nxt[maxn], res[maxn]; int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); std::cin >> Tim; while (Tim --> 0) { std::cin >> s + 1; n = strlen(s + 1), ans = 1; res[1] = 1; for (int i = 2, j = 0; i <= n; ++i) { while (j && s[i] != s[j + 1]) j = nxt[j]; nxt[i] = j += s[i] == s[j + 1], res[i] = res[j] + 1; } for (int i = 2, j = 0; i <= n; ++i) { while (j && s[i] != s[j + 1]) j = nxt[j]; j += s[i] == s[j + 1]; while (j > i / 2) j = nxt[j]; ans = static_cast<long long> (res[j] + 1) * ans % mod; } std::cout << ans << '\n'; } return 0; }