1052. 设计密码
题目链接
1052. 设计密码
你现在需要设计一个密码 \(S\),\(S\) 需要满足:
- \(S\) 的长度是 \(N\);
- \(S\) 只包含小写英文字母;
- \(S\) 不包含子串 \(T\);
例如:\(abc\) 和 \(abcde\) 是 \(abcde\) 的子串,\(abd\) 不是 \(abcde\) 的子串。
请问共有多少种不同的密码满足要求?
由于答案会非常大,请输出答案模 \(10^9+7\) 的余数。
输入格式
第一行输入整数\(N\),表示密码的长度。
第二行输入字符串\(T\),\(T\)中只包含小写字母。
输出格式
输出一个正整数,表示总方案数模 \(10^9+7\) 后的结果。
数据范围
\(1≤N≤50,\)
\(1≤|T|≤N,|T|\)是\(T\)的长度。
输入样例1:
2
a
输出样例1:
625
输入样例2:
4
cbc
输出样例2:
456924
解题思路
KMP+状态机dp
KMP匹配时 \(next\) 数组的定义:当前匹配的最长模式串的公共前后缀长度
-
状态表示:\(f[i][j]\) 表示字符串前 \(i\) 位且第 \(i\) 位在模式串中匹配的位置为 \(j\)
-
状态计算:\(f[i+1][p]+=f[i][j]\)
枚举第 \(i+1\) 位上的字符,由 \(next\) 数组可得该位在模式串的位置 \(p\),注意 \(p
- 时间复杂度:\(O(26nm^2)\)
代码
// Problem: 设计密码
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1054/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=55,mod=1e9+7;;
int n,m,ne[N],f[N][N];
char s[N];
int main()
{
cin>>n>>(s+1);
m=strlen(s+1);
for(int i=2,j=0;i<=n;i++)
{
while(j&&s[i]!=s[j+1])j=ne[j];
if(s[i]==s[j+1])j++;
ne[i]=j;
}
f[0][0]=1;
for(int i=0;i