【JZOJ4886】【NOIP2016提高A组集训第13场11.11】字符串

题目描述

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

数据范围

对于10%的数据,|str|=1
对于另30%的数据,n<=5
对于另30%的数据,危险串不存在相同字符
对于100%的数据,0<=|str|<=100,0<=n<=10000

解法

动态规划。
设f[i][j]表示到第i个字母,匹配到危险串的第j个字符。
显然

f[i][j]f[i+1][pos[j][k]]

pos[i][j]表示使用j这个字符匹配错误串,fail到的位置。
这个东西可以使用KMP得出。

代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define write(x) (cout<<(x)<<" ")
#define writeln(x) (cout<<(x)<<endl)
#define ll long long
using namespace std;
const char* fin="helloworld.in";
const char* fout="helloworld.out";
const ll inf=0x7fffffff;
const ll maxn=10007,maxm=107,mo=1000000007;
ll n,m,i,j,k,ans;
char a[maxm];
ll f[maxn][maxm];
ll p[maxn],pos[maxm][26];
ll read(){
    ll x=0,y=0;
    char ch=getchar();
    while (ch<'0' || ch>'9'){
        ch=getchar();
        if (++y==10) return -1;
    }
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
ll qpower(ll a,ll b){
    ll c=1;
    while (b){
        if (b&1) c=c*a%mo;
        a=a*a%mo;
        b>>=1;
    }
    return c;
}
bool prepare(){
    memset(f,0,sizeof(f));
    memset(a,0,sizeof(a));
    scanf("%s",a+1);
    m=strlen(a+1);
    if (a[1]<'a' || a[1]>'z'){
        ans=qpower(26,n);
        writeln(ans);
        n=0;
        for (i=1;i<=m;i++) n=n*10+a[i]-'0';
        return false;
    }else return true;
}
void kmp(){
    j=0;
    for (i=2;i<=m;i++){
        while (j && a[j+1]!=a[i]) j=p[j];       
        if (a[j+1]==a[i]) j++;
        p[i]=j;
    }
    for (i=0;i<m;i++)
        for (j='a';j<='z';j++){
            k=i;
            while (k && a[k+1]!=j) k=p[k];
            if (a[k+1]==j) pos[i][j-'a']=k+1;
            else pos[i][j-'a']=0;
        }
}
int main(){
    freopen(fin,"r",stdin);
    freopen(fout,"w",stdout);
    n=0;
    while (1){
        if (!n) n=read();
        if (n==-1) break;
        if (prepare()){
            kmp();
            f[0][0]=1;
            for (i=0;i<n;i++)
                for (j=0;j<m;j++)
                    for (k=0;k<26;k++){
                        f[i+1][pos[j][k]]=(f[i+1][pos[j][k]]+f[i][j])%mo;
                    }
            ans=0;
            for (i=0;i<m;i++) ans=(ans+f[n][i])%mo;
            writeln(ans);
            n=0;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hiweibolu/p/6714838.html