zoukankan      html  css  js  c++  java
  • bzoj1009 [HNOI2008]GT考试

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 4517  Solved: 2799
    [Submit][Status][Discuss]

    Description

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

    Input

      第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

    Output

      阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.

    Sample Input

    4 3 100
    111

    Sample Output

    81
    分析:以前做过一道类似的题:传送门,但是本题的n特别大,不能存到状态里面,怎么办? 
       如果当前匹配到不吉利数字的号码的第j位,枚举第j+1位的数字,能够转移到的地方是固定的. 构造一个转移矩阵,令a[i][j]表示不吉利数字的第i位跳到第j位有多少种方案. 这个很容易利用kmp算法求出来.那么f[i][j] = f[i-1][0] * a[0][j] + f[i - 1][1] * a[1][j] +......
    这是一个矩阵相乘的表达式,可以用矩阵快速幂来优化.
       通过矩阵快速幂,可以不用记录n,最后的答案就是矩阵第一行的和.因为第m列是不符合要求的,所以实际上只需要记录矩阵的0~m-1列即可.
       这道题的转移方式和那道题有很大的区别. 因为要用到矩阵快速幂不记录n,必须知道f[i][j]从哪些状态转移而来,转移过来的方案数是多少,那么就必须要求出a数组. 相反的,如果直接递推转移,那么很容易就能知道f[i][j]能够转移到哪些状态,直接从f[i][j] 转移到f[i + 1][k]即可.由此可以看出“转移到”和“转移来”有很大的区别,记录的东西也会有所不同.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int n,m,mod,nextt[30],ans;
    char s[30];
    
    struct node
    {
        int x[30][30];
        void clear()
        {
            memset(x,0,sizeof(x));
        }
    }a,b,c;
    
    void operator *= (node &p,node &q)
    {
        c.clear();
        for (int i = 0; i < m; i++)
            for (int j = 0; j < m; j++)
                for (int k = 0; k < m; k++)
                    c.x[i][j] = (c.x[i][j] + p.x[i][k] * q.x[k][j] % mod) % mod;
        p = c;
    }
    
    void kmp()
    {
        int j = 0;
        for (int i = 2; i <= m; i++)
        {
            while (j && s[j + 1] != s[i])
                j = nextt[j];
            if (s[j + 1] == s[i])
                j++;
            nextt[i] = j;
        }
        int k;
        b.clear();
        for (int i = 0; i < m; i++)
        {
            for (char j = '0'; j <= '9'; j++)
            {
                k = i;
                while (k && s[k + 1] != j)
                    k = nextt[k];
                if (s[k + 1] == j)
                    k++;
                b.x[i][k]++;
            }
        }
    }
    
    void qpow(int p)
    {
        a.clear();
        for (int i = 0; i < m; i++)
            a.x[i][i] = 1;
        while (p)
        {
            if (p & 1)
                a *= b;
            b *= b;
            p >>= 1;
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&mod);
        scanf("%s",s + 1);
        kmp();
        qpow(n);
        for (int i = 0; i < m; i++)
            ans = (ans + a.x[0][i]) % mod;
        printf("%d
    ",ans);
    
        return 0;
    }
        
  • 相关阅读:
    fzuoj Problem 2177 ytaaa
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Capture the Flag
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Team Formation
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Beauty of Array
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Lunch Time
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Convert QWERTY to Dvorak
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest May Day Holiday
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Demacia of the Ancients
    zjuoj The 12th Zhejiang Provincial Collegiate Programming Contest Ace of Aces
    csuoj 1335: 高桥和低桥
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8461466.html
Copyright © 2011-2022 走看看