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<m\),否则匹配成功即含有该子串,不合题意

  • 时间复杂度:\(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 <bits/stdc++.h>
 
//#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<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> 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<n;i++)
    	for(int j=0;j<=m;j++)
    		for(int k=0;k<26;k++)
    		{
    			int p=j;
    			while(p&&k!=(s[p+1]-'a'))p=ne[p];
    			if(k==(s[p+1]-'a'))p++;
    			if(p<m)f[i+1][p]=(f[i+1][p]+f[i][j])%mod;
    		}
    int res=0;
    for(int i=0;i<m;i++)res=(res+f[n][i])%mod;
    cout<<res;
    return 0;
}
posted @ 2022-03-12 12:39  zyy2001  阅读(129)  评论(0编辑  收藏  举报