[kmp + 狀態機DP]
阿新 • • 發佈:2022-03-17
你現在需要設計一個密碼 S,S 需要滿足:
S 的長度是 N;
S 只包含小寫英文字母;
S 不包含子串 T;
例如:abc 和 abcde 是 abcde 的子串,abd 不是 abcde 的子串。
請問共有多少種不同的密碼滿足要求?
由於答案會非常大,請輸出答案模 109+7 的餘數。
輸入格式
第一行輸入整數N,表示密碼的長度。
第二行輸入字串T,T中只包含小寫字母。
輸出格式
輸出一個正整數,表示總方案數模 109+7 後的結果。
資料範圍
1≤N≤50,
1≤|T|≤N,|T|是T的長度。
輸入樣例1:
2
a
輸出樣例1:
625
輸入樣例2:
4
cbc
輸出樣例2:
456924
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 55, MOD = 1e9 + 7; //f[i][j]:表示生成了前i個字元,和T已經匹配到第j個字元的方案數; int f[N][N]; int n, m; char str[N]; int main() { cin >> n >> str + 1; //從1開始; m = strlen(str + 1); int ne[N] = {0}; //求next[]陣列; for (int i = 2, j = 0; i <= n; 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++) //列舉前i個字元; for (int j = 0; j < m; j++) //列舉第i位密碼匹配到的子串位置都列舉一遍; for (int k = 'a'; k <= 'z'; k++) //即列舉第i+1個位位置上的字元; { int u = j; //做KMP匹配; while (u && k != str[u + 1]) u = ne[u]; if (k == str[u+1]) u++; if (u < m) f[i+1][u] = (f[i+1][u] + f[i][j]) % MOD; } int res = 0; for (int i = 0; i < m; i++) res = (res + f[n][i]) % MOD; cout << res << endl; return 0; }