Count the string(前缀出现次数

题目描述:

Count the string(前缀出现次数_第1张图片

题意:

输出所有s中前缀在s中出现的次数。

思路:

拿到这题刚开始的时候我是没有头绪的。当然,DP问题本来就是一个玄学,再加上这题还得用到KMP算法对字符串进行处理,很难想到用DP去求解(是我太菜了QAQ),我们用dp[i]表示i前面所出现的前缀重复的次数,因为KMP算法中next数组的定义,next[i]就是在i前面前缀重复的上一个位置,这个说法可能不怎么好理解,这里小编再做一个详细的解释,就比如aabaabaabaab这个字符串,next[6] = 3,next[9] = 6,next[12] = 6,因为next数组表示的是前缀后缀最大匹配长度,所以如果i-next[i]就是前缀的长度,而next[i]的值就是在这个字符串中上一次重复到这个前缀的位置。说到这里可能有人要问小编,这有什么用呢?得到了这个我就可以写出一个状态转移方程了,dp[i] = dp[next[i]] + 1,DP问题从来都是玄学……想到了这里的话这道题就可以dp迭代一下子就完成了。

参考代码:

#include 
using namespace std;
const int N=1e6+10;
#define end '\n'
#define IOS ios::sync_with_stdio(0)
int nxt[N],len=0,dp[N],mod=10007;
void get_next(string p) {
    int j = 0, k = -1;
    nxt[0] = -1;
    while (j < len)
        if (k == -1 || p[j] == p[k])
            nxt[++j] = ++k;
        else
            k = nxt[k];
}
int main() {
    string a;
    IOS;
    int t;
    cin >> t;
    while (t--) {
        cin >> len;
        cin >> a;
        get_next(a);
        memset(dp, 0, sizeof(dp));
        int sum = 0;
        for (int i = 1; i <= len; i++) {
            dp[i] = dp[nxt[i]] + 1;
            sum = (sum + dp[i]) % mod;
        }
        cout << sum << end;
    }
    return 0;
}

你可能感兴趣的:(#,做题心得,#,DP,字符串,字符串,dp)