【NOIP2016提高A組集訓第13場11.11】字串
阿新 • • 發佈:2019-01-09
Description
某日mhy12345在教同學們寫helloworld,要求同學們用程式輸出一個給定長度的字串,然而發現有些人輸出了一些“危險”的東西,所以mhy12345想知道對於任意長度n的小寫字母字串,不包含危險串的字串個數
Solution
一開始還打容斥,沒有往動態規劃的方向去想,但是這是一個很簡單的動態規劃的題目。
那麼直接設f[i][j]為做到字串第i個,危險串匹配到第j個。那麼設c[i][j]為危險串第i個要做到第j個字元會到第c[i][j]的位置。
那麼就有一個DP方程
那麼因為不能包含整個危險串 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);
}
}