Description

某日mhy12345在教同学们写helloworld,要求同学们用程序输出一个给定长度的字符串,然而发现有些人输出了一些“危险”的东西,所以mhy12345想知道对于任意长度n的小写字母字符串,不包含危险串的字符串个数

Solution

一开始还打容斥,没有往动态规划的方向去想,但是这是一个很简单的动态规划的题目。
那么直接设f[i][j]为做到字符串第i个,危险串匹配到第j个。那么设c[i][j]为危险串第i个要做到第j个字符会到第c[i][j]的位置。
那么就有一个DP方程f[i+1][c[j][k]]+=f[i][j]
那么因为不能包含整个危险串ans=∑m−1i=0f[n][i]

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=10007,mo=1e9+7;
typedef long long ll;
int i,j,k,l,t,n,m;
char s[maxn];
int a[maxn],b[maxn],p[maxn];
bool az;
ll ans,f[maxn][107],c[maxn][27];
int main(){
// freopen("fan.in","r",stdin);
freopen("helloworld.in","r",stdin);
freopen("helloworld.out","w",stdout);
while(scanf("%d",&n)!=EOF){
scanf("%s",s+1);
m=strlen(s+1);az=0;
fo(i,1,m)a[i]=s[i]-'a';
fo(i,1,m)if(s[i]>'z'||s[i]<'a')az=1;
memset(p,0,sizeof(p));
j=0;ans=0;
fo(i,2,m){
if(j&&s[j+1]!=s[i])j=p[j];
if(s[j+1]==s[i])j++;
p[i]=j;
}
fo(i,0,m-1){
fo(j,0,25){
k=i;
while(k&&a[k+1]!=j)k=p[k];
if(a[k+1]==j)k++;
c[i][j]=k;
}
}
memset(f,0,sizeof(f));f[0][0]=1;
fo(i,0,n-1){
fo(j,0,m-1){
fo(k,0,25){
f[i+1][c[j][k]]=(f[i+1][c[j][k]]+f[i][j])%mo;
}
}
}
fo(i,0,m-1)ans=(ans+f[n][i])%mo;
printf("%lld\n",ans);
}
}