• AcWing-1052. 设计密码(kmp+复杂状态机+动态规划)


    题目描述

    你现在需要设计一个密码 S,S 需要满足:
    
    S 的长度是 N;
    S 只包含小写英文字母;
    S 不包含子串 T;
    例如:abc 和 abcde 是 abcde 的子串,abd 不是 abcde 的子串。
    
    请问共有多少种不同的密码满足要求?
    
    由于答案会非常大,请输出答案模 1e9+7 的余数。
    
    输入格式
    第一行输入整数N,表示密码的长度。
    
    第二行输入字符串T,T中只包含小写字母。
    
    输出格式
    输出一个正整数,表示总方案数模 109+7 后的结果。
    
    数据范围
    1≤N≤50,
    1|T|≤N ,|T|是T的长度。
    
    输入样例12
    a
    
    输出样例1625
    
    输入样例24
    cbc
    
    输出样例2456924
    

    思路

    状态定义:

    • f[i][j]代表字符串长度为i且状态机状态为j的方案数。
      初始状态有f[0][0] = 1, f[0][1 ~ (m - 1)] = 0
      在这里插入图片描述

    最后把所有可能的 j 的位置加起来,就是答案,因为i最后肯定是 n ,所以枚举一下未知的 j 。

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 52, MOD = 1e9 + 7;
    
    int n;
    char str[N];
    int ne[N];
    int f[N][N];
    //f[i][j]表示串S前i位为与串T前j位匹配成功,第i位匹配到子串中位置位j时(S[i - j + 1 ~ i] == T[1 ~ j])的方案数
    
    int main() {
        cin >> n >> (str + 1);
        int m = strlen(str + 1);
    
        for (int i = 2, j = 0; i <= m; ++i) {
            while (j && str[i] != str[j + 1]) j = ne[j];
            if (str[i] == str[j + 1]) ++j;
            ne[i] = j;
        }
    
        f[0][0] = 1;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                for (char k = 'a'; k <= 'z'; ++k) { //假定S[i + 1]位为k,与T[j + 1]位进行匹配判断
                    int u = j;
                    while (u && k != str[u + 1]) u = ne[u];
                    if (k == str[u + 1]) ++u;
                    //f[i + 1][u]代表串S前i+1位与串前jj位匹配成功(S[i+1-u+1~i+1] == T[1~u])方案数
                    if (u < m)f[i + 1][u] = (f[i + 1][u] + f[i][j]) % MOD;
                    //f[i][j]可以通过i+1赋值为k到达f[i+1][u]点(新增路径)
                    //注:可能存在重边,因为j不同但ne[j]是相同的,并且k是相同的,所以此时
                    //f[i][j1]和f[i][j2]跳到的位置是一样的(k相同,ne[j1]=ne[j2])
                }
            }
        }
    
        int res = 0;
        for (int i = 0; i < m; ++i) res = (res + f[n][i]) % MOD;
        cout << res << endl;
    
        return 0;
    }
    
  • 相关阅读:
    通过前序遍历和中序遍历确定二叉树,并输出后序遍历序列
    浅谈c语言和c++中struct的区别
    KFCM算法的matlab程序
    聚类——KFCM
    FCM算法的matlab程序2
    GMM算法的matlab程序
    FCM算法的matlab程序
    K-means算法的matlab程序
    GMM算法的matlab程序(初步)
    FCM算法的matlab程序(初步)
  • 原文地址:https://www.cnblogs.com/zdw20191029/p/14553296.html
Copyright © 2020-2023  润新知