BZOJ 1009 [HNOI2008]GT考试

设dp[i][j]为当前是第i位考号、现在匹配到A的第j位的方案数

因为假如当前匹配j位,如果选择的下一位与A[j+1]不同,新的匹配位数是num(fail[j])而不是0

设由匹配j位转移到匹配k位的方案数为c[j][k]那么

$dp[i][j] = \sum f[i-1][k]*c[k][j] $


这个式子是线性的,计算出t矩阵的n次幂,乘以初始矩阵
c矩阵枚举当前匹配多少位,利用KMP计算c矩阵

 

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 33;
int n,m,k,T[maxn],next[maxn];
struct Matrix {
    int f[maxn][maxn];
    Matrix () { memset(f,0,sizeof f);};
    void clear() { memset(f,0,sizeof f);};
}a,F;
Matrix operator * (const Matrix & a,const Matrix & b) {
    Matrix ret;
    for(int i=0;i<m;++i)
        for(int j=0;j<m;++j)
            for(int kk=0;kk<m;++kk) 
                ret.f[i][j]=(ret.f[i][j]+a.f[i][kk]*b.f[kk][j])%k;
    return ret;
}
void get_next() {
    next[1]=0;
    for(int j=0,i=2;i<=m;++i) {
        for(;j && T[j+1] != T[i];j=next[j]);
        if(T[j+1]==T[i]) ++j; next[i]=j;
    }
}
void get_a() {
    for(int i=0;i<m;++i) 
        for(int k,j=0;j<10;++j) {
            for(k=i; k && T[k+1]!=j; k=next[k]);
            if(T[k+1]==j) ++k;
            a.f[i][k]++;
        }
}
void pow() {
    Matrix tmp=a;
    a.clear();
    for(int i=0;i<m;++i) a.f[i][i]=1;
    for(;n;n>>=1,tmp=tmp*tmp) if(n&1) a=a*tmp;
}
int main() {
    char c[maxn];
    scanf("%d%d%d%s",&n,&m,&k,c+1);
    for(int i=1;i<=m;++i) T[i]=c[i]-'0';
    get_next();get_a();pow();
    int Ans=0;
    F.f[0][0]=1;
    F=F*a;
    for(int i=0;i<m;++i) Ans=(Ans+F.f[0][i])%k;
    printf("%d\n",Ans);
}

 

posted @ 2018-03-20 21:31  zzzzx  阅读(273)  评论(0编辑  收藏  举报