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

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 4024  Solved: 2452 [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
     
    设$dp[i][j]$表示前i个字符,且后缀为不吉利数字的前缀的最长长度为j的方案数,那么显然$ans = sum_{i=1}^{m-1} dp[n][i]$
    设$num[i][j]$为在长度为$i$的不吉利数字的前缀后加一个数使得后缀为不吉利数字的前缀的最长长度为$j$的方案数,$num$数组可以用kmp求出来
    转移为$dp[k][j] = sum_{i = 1}^{m - 1} dp[k -1][i] * num[i][j]$
    对于同一串不吉利数字$num$数组为常数,那么可以利用矩阵加速递推
     
    #include <cstdio>
    #include <cstring> 
    const int maxm = 25;
    int mod;
    struct matrix{
        int n, m, num[maxm][maxm];
        matrix(){}
        matrix(int _n, int _m){
            n = _n;
            m = _m;
            memset(num, 0, sizeof num);
        }
        matrix operator * (const matrix &a){
            matrix b(n, a.m);
            for(int i = 0; i < n; i++)
                for(int j = 0; j < a.m; j++)
                    for(int k = 0; k < m; k++)
                        (b.num[i][j] += num[i][k] * a.num[k][j]) %= mod;
            return b;
        }
    };
    matrix ksm(matrix a, int b){
        matrix s(a.m, a.m);
        for(int i = 0; i < s.m; i++)
            s.num[i][i] = 1;
        while(b){
            if(b & 1) s = s * a;
            b >>= 1;
            a = a * a;
        }
        return s;
    }
    int n, m;
    char A[maxm];
    int p[maxm];
    int main(){
        scanf("%d %d %d", &n, &m, &mod);
        scanf("%s", A + 1);
        p[1] = 0;
        for(int j = 0, i = 2; i <= m; i++){
            while(A[i] != A[j + 1] && j) j = p[j];
            if(A[i] == A[j + 1]) j++;
            p[i] = j;
        }
        matrix ans(1, m), zy(m, m);
        for(int i = 0; i < m; i++)
            for(int j = '0'; j <= '9'; j++){
                int k = i;
                while(k && A[k + 1] != j) k = p[k];
                if(A[k + 1] == j) k++;
                if(k != m) zy.num[i][k]++;
            }
        ans.num[0][0] = 1;
        ans = ans * ksm(zy, n);
        int aa = 0;
        for(int i = 0; i < m; i++)
            (aa += ans.num[0][i]) %= mod;
        printf("%d
    ", aa);
        return 0;
    }
  • 相关阅读:
    【NX二次开发】Block UI 组
    【NX二次开发】Block UI 双精度表
    【NX二次开发】Block UI 整数表
    自己写的简单的轮播图
    微信分享到朋友圈----摘录
    HTML5比较实用的代码
    苏格拉底的名言警句
    jQuery 幻灯片 ----摘录
    DeDe调用指定栏目ID下的文章
    JQuery 判断ie7|| ie8
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7440350.html
Copyright © 2011-2022 走看看