1. 程式人生 > >【NOIP2016提高A組集訓第13場11.11】字串

【NOIP2016提高A組集訓第13場11.11】字串

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); } }