题目链接
题意
给定一个串 S ,求其所有前缀在其中的出现次数的总和。
思路
考虑
记 dp[i] 为以 i 结尾的串中与前缀相同的串的个数。
由
而在
S[0..j−1]
中又有
S[0..km]==S[j−1−km,j−1],0≤m≤dp[j]
故有
S[0..ki]==S[i−1−ki,i−1],0≤m≤dp[j]
即 S[0..j−1] 中出现的所有与前缀相同的串,其在 S[i−j,i−1] 中也出现,即 dp[i] 至少等于 dp[j] .
另外,其本身 S[0..i−1] 也是一个前缀,所以再 +1 .
最后,是否有遗漏呢?
假设漏算了一些串,它们对应前缀的结束位置在
j−1
之后,那么,
fail[i]>j
,矛盾。
故 dp[i] 即为上面所提的两部分之和, dp[i]=dp[j]+1 ,表示以 i 结尾的串中与前缀相同的串的个数。
最后求个
Code
#include <bits/stdc++.h>
#define maxn 200010
using namespace std;
const int mod = 10007;
typedef long long LL;
char s[maxn];
int f[maxn], n, dp[maxn];
void getfail() {
f[0] = f[1] = 0;
for (int i = 1; i < n; ++i) {
int j = f[i];
while (j && s[i] != s[j]) j = f[j];
f[i+1] = s[i] == s[j] ? j+1 : 0;
}
}
void work() {
scanf("%d%s", &n, s);
getfail();
int ans = 0;
for (int i = 1; i <= n; ++i) {
(dp[i] = dp[f[i]] + 1) %= mod;
(ans += dp[i]) %= mod;
}
printf("%d\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}