zoukankan      html  css  js  c++  java
  • 题解:BZOJ 1009 HNOI2008 GT考试 KMP + 矩阵

    原题描述:

    阿申准备报名参加GT考试,准考证号为N位数 X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai& lt;=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0

    分析:

    吐槽:这道题的细节问题差点坑死我。

    一开始这道题想了个DP,但是状态转移太恶心。

    那我们换一个思路,先用KMP构造出A的一个自动机。

    然后这道题就转化成了在自动机上跑啊跑,跑N条边都没跑到终态(Am)的路径数。

    这样,我们就把这道题转化成了一个经典问题:在一个有向图上,从s到t,经过N条边的路径数。

    矩阵快速幂即可解决。

    不会做的个经典问题的话,请看下面的讲解:

    /*

    这个问题我们可以用DP解决,方程为:

    DP[i][j][k] = DP[i][p][k - 1] * DP[p][j][k - 1];

    然后,显然,我们可以利用滚动数组。

    DP[i][j] = DP[i][p] * DP[p][j];

    然后,然后,你发现了什么?

    这不是矩阵乘法么!

    */

    具体实现过程:

    1. 求得A的Next数组。

    2. 根据转移图构造矩阵M:i能转移到j则,M[i][j] ++;

    (由于Am是终态,所以可以不向Am连边,常数优化)

    3. C = M ^ n;

    4. 答案为for(int I = 0;I < m;I ++) ans +=C[0][i];

    ACCode:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    int N,M,K;
    
    const int maxm = 30;
    
    struct Matrix
    {
        int a[maxm][maxm],n;
        Matrix(int n,int x) : n(n)
        {
            for(int i = 0;i < n;i ++)   for(int j = 0;j < n;j ++)   a[i][j] = i == j ? x : 0;
        }
        Matrix operator * (const Matrix &b)
        {
            Matrix c(n,0);
            for(int i = 0;i < n;i ++)
            for(int j = 0;j < n;j ++)
            for(int k = 0;k < n;k ++)
                (c.a[i][j] += ((a[i][k] * b.a[k][j]) % K)) %= K;
            return c;
        }
    };
    
    Matrix pow_mod(Matrix &a,int b)
    {
        Matrix c(a.n,1);
        for(; b ;b >>= 1)
        {
            if(b & 1)   c = c * a;
            a = a * a;
        }
        return c;
    }
    int A[maxm],f[maxm];
    Matrix m(maxm,0);
    
    void getNext()
    {
        for(int i = 1;i < M;i ++)
        {
            int j = f[i];
            while(j && A[i] != A[j])    j = f[j];
            f[i + 1] = A[i] == A[j] ? j + 1 : 0;
        }
    }
    
    char str[maxm];
    
    int main()
    {
        scanf("%d%d%d\n%s",&N,&M,&K,str);
        for(int i = 0;i < M;i ++)  A[i] = str[i] - '0';
        getNext();
        m.n = M;
        for(int i = 0;i < M;i ++)
        for(int j = 0;j < 10;j ++)
        {
            int k = i;
            if(A[i] == j)   m.a[i][i + 1] ++;
            else
            {
                while(k && A[k] != j)   k = f[k];
                if(A[k] == j)   k ++;
                m.a[i][k] ++;
            }
        }
        Matrix c = pow_mod(m,N);
        int ans = 0;
        for(int i = 0;i < M;i ++)  (ans += c.a[0][i]) %= K;
        printf("%d\n",ans);
        return 0;
    }
  • 相关阅读:
    求正整数N(N>1)的质因数的个数。
    手机键盘输入字母
    第二部分进度
    第一部分:地域维度标准化
    利用python解析地址经纬度
    输入任意4个字符(如:abcd), 并按反序输出(如:dcba)
    python-->微信支付
    python-图片流传输(url转换二维码)
    python-qrcode-二维码
    ajax和axios、fetch的区别
  • 原文地址:https://www.cnblogs.com/vivym/p/3927977.html
Copyright © 2011-2022 走看看