一、內容
你現在需要設計一個密碼 S,S需要滿足:S的長度是 N;S只包含小寫英文字母;S不包含子串 T ;例如:ab和 abcde 是 abcde 的子串,abd 不是 abcde的子串。請問共有多少種不同的密碼滿足要求?由於答案會非常大,請輸出答案模 109+7的餘數。
輸入格式
第一行輸入整數N,表示密碼的長度。第二行輸入字符串T,T中只包含小寫字母。
輸出格式
輸出一個正整數,表示總方案數模 109+7後的結果。
數據範圍
1≤N≤50,1≤|T|≤N,|T|是T的長度。
輸入樣例1:
2
a
輸出樣例1:
625
二、思路
三、代碼
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5005, MOD = 1e9+7;
int n, m, ne[N], netj[27][N], f[N][N];
char s[N];
void getNext() {
ne[1] = 0;
for (int i = 2, j = 0; i < m; i++) {
while (j && s[i] != s[j + 1]) j = ne[j];
if (s[i] == s[j + 1]) j++;
ne[i] = j;
}
}
void init() {
for (int k = 0; k < 26; k++) {
for (int j = 0; j < m; j++) {
int tj = j;
char c = (char)(k + 'a');
while (tj && c != s[tj + 1]) tj = ne[tj];
if (c == s[tj + 1]) tj++;
netj[k][j] = tj; //記錄最終跳的位置
}
}
}
int main() {
scanf("%d%s", &n, s + 1);
m = strlen(s + 1);
getNext();
init(); //預處理
f[0][0] = 1;
//f[i][j] 代表匹配到i這個字符,匹配串位置爲j的種數
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) { //枚舉所有的狀態
for (int k = 0; k < 26; k++) {
// char c = (char)('a' + k);
// int tj = j;
// while (tj && c != s[tj + 1]) tj = ne[tj];
// if (c == s[tj + 1]) tj++; //最終會跳的位置
int tj = netj[k][j];
//由(i-1,j)的狀態跳到 (i, tj)的狀態
if (tj < m) f[i][tj] = (f[i][tj] + f[i - 1][j]) % MOD;
}
}
}
int ans = 0;
for (int j = 0; j < m; j++) ans = (ans + f[n][j]) % MOD;
printf("%d", ans);
return 0;
}