設計密碼 狀態機 + KMP

一、內容

你現在需要設計一個密碼 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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章