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;
    }
  • 相关阅读:
    Spring Boot 启动加载数据 CommandLineRunner(一般用于项目启动时,用户信息的缓存)
    缓存穿透、缓存并发、缓存失效之思路变迁
    知识点的梳理
    windows下查找java应用占用CPU过高问题
    Java开发中的Memcache原理及实现
    malloc函数详解 C语言逻辑运算符
    PCH 警告:标头停止点不能位于宏或#if块中
    绪论-第一章-《数据结构题集》
    线性表的顺序存储结构--用数组实现
    第二章 《C++ Primer Plus》
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7440350.html
Copyright © 2011-2022 走看看