题目描述
你现在需要设计一个密码 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
题目思路
- 寻找最优子结构
S 的长度是 N;
S 只包含小写英文字母;
S 不包含子串 T;
- 题目分析
题目的限制条件中说不能包含相同的子串,那么我们就会想到KMP,因为KMP解决的就是这类问题。
求数量的话,我们可能会想到数学方法或者是DP方法,两种方法依次尝试,看哪一种更合适一点。
尝试之后发现,就是要使用KMP+DP做这个题目。
- DP集合分析
因为会输入长度,那么长度这个变量是要加入集合表示中的。
接下来考虑它是如何进行转移的,KMP的写法中,它的匹配是一个跳一个的,那么我就依据这个来分析他的状态转移方程。
一个状态转移为另一个状态,这不就是状态机吗。
使用状态机的DP思路思考。
f
[
i
,
j
]
f[i, j]
f[i,j]
集合表示:有长度为i,最后一个字符状态为j的符合条件的字符串数量。
属性:数量。
状态划分就是以j的下一个状态的点为分界点就行组合。
在每一个位置枚举26个字母,也就是将所有情况都枚举了一遍,我们只需要KMP数组中的长度没有达到序列的总长度即表示这种情况没有包含子串T。
- 初始化
在长度为0,状态为0的时候,是算作一种情况。
AC 代码 O ( N 3 ) O(N^3) O(N3)
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << ENDL
#define mod(x) (x) % MOD
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 50 + 5, MOD = 1e9 + 7;
int f[N][N], ne[N];
char T[N];
int main() {
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif // LOCAL
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin >> n >> T + 1;
int m = strlen(T + 1);
for (int i = 2, j = 0; i <= m; ++i) {
while (j && T[i] != T[j + 1]) j = ne[j];
if (T[i] == T[j + 1]) ++j;
ne[i] = j;
}
f[0][0] = 1;
_for(i, 0, n) _for(j, 0, m) for (char k = 'a'; k != 'z' + 1; ++k) {
int u = j;
while (u && k != T[u + 1]) u = ne[u];
if (T[u + 1] == k) ++u;
if (u < m) f[i + 1][u] = mod(f[i + 1][u] + f[i][j]);
}
int ans = 0;
_for(i, 0, m) ans = mod(ans + f[n][i]);
cout << ans << ENDL;
return 0;
}
AC 代码 O ( N 2 ) 预 处 理 O(N^2)预处理 O(N2)预处理
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << ENDL
#define mod(x) (x) % MOD
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 50 + 5, MOD = 1e9 + 7;
int f[N][N], ne[N], last[N][26];
char T[N];
int main() {
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif // LOCAL
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin >> n >> T + 1;
int m = strlen(T + 1);
for (int i = 2, j = 0; i <= m; ++i) {
while (j && T[i] != T[j + 1]) j = ne[j];
if (T[i] == T[j + 1]) ++j;
ne[i] = j;
}
_for(j, 0, m) for (char k = 'a'; k != 'z' + 1; ++k) {
int u = j;
while (u && k != T[u + 1]) u = ne[u];
if (T[u + 1] == k) ++u;
last[j][k - 'a'] = u;
}
f[0][0] = 1;
_for(i, 0, n) _for(j, 0, m) for (char k = 'a'; k != 'z' + 1; ++k) {
int u = last[j][k - 'a'];
if (u < m) f[i + 1][u] = mod(f[i + 1][u] + f[i][j]);
}
int ans = 0;
_for(i, 0, m) ans = mod(ans + f[n][i]);
cout << ans << ENDL;
return 0;
}