[HNOI2008]GT考试

题目链接:Click here

Solution:

考虑dp,\(f[i][j]\)表示已经确定了\(i\)位,当前匹配到第\(j\)位的方案数

给出的字符串是固定,不难发现我们每次转移的方程也是一个与上次状态无关的固定的东西

\[f[i][j]=\sum_{k=0} ^{m-1} f[i-1][k]\times g[k][j] \]

显而易见的是,这是一个矩乘的模式,而转移矩阵\(g\)我们可以通过\(kmp\)很快的求出来

那么我们矩乘优化dp即可,时间复杂度\(O(m^3 \lg n)\)

Code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=21;
int n,m,mod,ans,nxt[M];
char s[M];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
struct Matrix{
    int l,r,a[M][M];
    void init(int L,int R){
        l=L;r=R;
        memset(a,0,sizeof(a));
    }
    void IE(){for(int i=0;i<M;i++)a[i][i]=1;}
    friend Matrix operator *(Matrix u,Matrix v){
        Matrix t;t.init(u.l,v.r);
        for(int i=0;i<u.l;i++)
            for(int j=0;j<v.r;j++)
                for(int k=0;k<u.r;k++)
                    t.a[i][j]=(t.a[i][j]+(u.a[i][k]*v.a[k][j]%mod))%mod;
        return t;
    }
};
Matrix qpow(Matrix a,int b){
    Matrix re;re.init(m,m);re.IE();
    while(b){
        if(b&1) re=re*a;
        b>>=1;a=a*a;
    }return re;
}
Matrix kmp(){
    for(int i=2,j=0;i<=m;i++){
        while(j&&s[j+1]!=s[i]) j=nxt[j];
        if(s[j+1]==s[i]) ++j;
        nxt[i]=j;
    }
    Matrix tmp;tmp.init(m,m);
    for(int i=0;i<m;i++)
        for(char j='0';j<='9';j++){
            int k=i;
            while(k&&s[k+1]!=j) k=nxt[k];
            if(s[k+1]==j) ++k;
            ++tmp.a[i][k];
        }
    return tmp;
}
signed main(){
    n=read(),m=read(),mod=read();
    scanf("%s",s+1);
    Matrix trans;trans=kmp();
    trans=qpow(trans,n);
    for(int i=0;i<m;i++) ans=(ans+trans.a[0][i])%mod;
    printf("%lld\n",ans);
    return 0;
}

posted @ 2020-01-21 12:00  DQY_dqy  阅读(147)  评论(0编辑  收藏  举报