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

10 篇文章 0 订阅
9 篇文章 0 订阅

题目链接

题意

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

思路

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

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

fail[i]=j S[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 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值