BZOJ 1009--GT考试(KMP&DP&矩阵乘法)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1009--GT考试(KMP&DP&矩阵乘法)相关的知识,希望对你有一定的参考价值。

    RP++

题目链接:

     http://www.lydsy.com/JudgeOnline/problem.php?id=1009 

Solution

    考虑DP。。。

    dp [ i ] [ j ] 表示现在放完了 i 位,没有出现不吉利数字,但是末尾已经与不吉利数字最多对应了j 位的情况的数量

    状态转移方程。。。说起来很麻烦但很显然

    先对“不吉利数字”做KMP,然后就可以根据此时状态进行DP。。

    但是发现 i 这一维太大了。。。不论时间还是空间都是不允许的。。

    于是要用矩阵乘法加速DP。。。

    具体实现还是直接看代码吧。。。。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define M 1010
#define LL long long
#define mod 1000000007
using namespace std;
int n,m,p;
int nxt[M];
char s[25];
struct jz{
    int x[22][22];
    friend jz operator *(const jz &a,const jz &b){
        jz tmp;
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++){
                tmp.x[i][j]=0;
                for(int k=0;k<m;k++)
                    tmp.x[i][j]=(tmp.x[i][j]+a.x[i][k]*b.x[k][j])%p;
            }
        return tmp;
    }
}a,b;
void KMP(){
    int f=0;
    for(int i=2;i<=m;i++){
        while(f>0&&s[f+1]!=s[i]) f=nxt[f];
        if(s[f+1]==s[i]) f++;
        nxt[i]=f;
    }
    for(int i=0;i<m;i++)
        for(int j=‘0‘;j<=‘9‘;j++){
            f=i;
            while(f>0&&s[f+1]!=j) f=nxt[f];
            if(s[f+1]==j) b.x[i][f+1]++;
            else b.x[i][0]++;
        }
}
void pow(){
    while(n){
        if(n&1) a=a*b;
        n>>=1;
        b=b*b;
    }
}
int main(){
    int ans=0;
    scanf("%d%d%d",&n,&m,&p);
    scanf("%s",s+1);
    KMP();
    for(int i=0;i<m;i++)
        a.x[i][i]=1;
    pow();
    for(int i=0;i<m;i++)
        ans=(ans+a.x[0][i])%p;
    printf("%d\n",ans);
    return 0;
}

  

  

This passage is made by Iscream-2001.

以上是关于BZOJ 1009--GT考试(KMP&DP&矩阵乘法)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1009 GT考试 (kmp+矩阵优化dp)

[HNOI2008][bzoj1009] GT考试 [KMP+矩阵快速幂]

[BZOJ1009] [HNOI2008] GT考试 (KMP & dp & 矩阵乘法)

BZOJ1009 GT考试

bzoj 1009 GT考试

BZOJ 1009 GT考试