Count the string HDU - 3336 (KMP next 不一样的用法(动态规划))

Count the string HDU - 3336
It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: “abab”
The prefixes are: “a”, “ab”, “aba”, “abab”
For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.
Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.
Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.
Sample Input
1
4
abab
Sample Output
6

这道题呢 又是 KMP next 数组 的 一个 不一样的用法,这个用法呢 不是太好理解,但是呢 也不是很难的,;-)。 先说一下 题目的大概意思:首先给你一个字符串, 然后 让你查找 该字符串 的每一个 前缀(注意 是 前缀 ,要区别 真前缀),在 字符串中的匹配 次数,然后 算出 匹配次数的累加和 , 输出即可。思考一下 如果 你 把 每一个前缀都循环一边的 话 肯定会 超时的 ,这 就要用到 next 数组啦, 先 定义一个 dp 数组, 看到 dp 大家 应该 就知道 会用 到动态规划啦,dp【i】 表示的意思是, 字符串的前 i 个 字符中, 以 第 i 个 字符 为 结尾的 前缀的 个数, 但是 不包括 自己本身,动态转移方程 为 : dp[i] = dp[next[i]] + 1; 提示 一点 这里的 next 【i】 存储的 是 , 0 -> i-1 对应字符的 匹配 数 , 而 有的 朋友 学习的 next数组 是存储的 包括 当前字符 的 匹配数, 具体 看 代码, 两种 方法的 最大区别就是 , 一个是,next【0】 = -1(该题 需要的 类型 数组), 另一种 的是 next【0】 = 0; 这 里的 动态转移方程 不是太好理解, 结合 这 对 next 数组的 理解 ,还是可以 相同的,next 数组的 所表示的意思就 是 当前 前面的 子字符串 中 与 前缀 的 匹配长度。 大家好好理解!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

void GetNext(char *p, int *next)
{
    int p_len = strlen(p);
    int i = 0;
    int j = -1;
    next[0] = -1;
    while(i < p_len)
    {
        if(j == -1 || p[i] == p[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

int main()
{
    int t; cin>>t;

    while(t--)
    {
        int n;
        static char p[200010];
        int next[200010];
        int dp[200010];

        scanf("%d", &n);
        scanf(" %s", p);
        GetNext(p, next);
        memset(dp, 0, sizeof(dp));
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            dp[i] = dp[next[i]] + 1;
            ans = (ans + dp[i]) % 10007;
        }

        printf("%d\n", ans);
    }


    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值