HDU 3336 Count the string 所有前缀在串中的出现总次数

来源:互联网 发布:极路由网络唤醒 编辑:程序博客网 时间:2024/06/07 12:55

题目链接

题意

给定一个串 S,求其所有前缀在其中的出现次数的总和。

思路

考虑 fail 数组,fail[i]=j 的含义是 S[0..j1]==S[ij..i1].

dp[i] 为以 i 结尾的串中与前缀相同的串的个数。

fail[i]=jS[0..j1]==S[ij..i1]
而在 S[0..j1] 中又有 S[0..km]==S[j1km,j1],0mdp[j]
故有 S[0..ki]==S[i1ki,i1],0mdp[j]

S[0..j1] 中出现的所有与前缀相同的串,其在 S[ij,i1] 中也出现,即 dp[i] 至少等于 dp[j].

另外,其本身 S[0..i1] 也是一个前缀,所以再 +1.

最后,是否有遗漏呢?
假设漏算了一些串,它们对应前缀的结束位置在 j1 之后,那么,fail[i]>j,矛盾。

dp[i] 即为上面所提的两部分之和,dp[i]=dp[j]+1,表示以 i 结尾的串中与前缀相同的串的个数。

最后求个 ni=1dp[i],即为答案。

Code

#include <bits/stdc++.h>#define maxn 200010using 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;}
阅读全文
0 0
原创粉丝点击