• BZOJ 1009 HNOI 2008 GT考试 递推+矩乘


    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3679  Solved: 2254
    [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

    Solution

    如果n很小的话,可以直接做数位DP,但是现在n很大,需要用到矩乘。

    设F[i][j]表示准考证号前i位中匹配到不吉利数串的第j个的方案数。

    我们很容易发现,F数组存在一定的转移关系。

    转移时考虑当前匹配到不吉利串的第i个,下一个数字填0~9时,转移到匹配到不吉利串的第j个,匹配过程可以KMP,这样就可以构造出转移矩阵。

    Code

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    10 #define mset(a, b) memset(a, b, sizeof(a))
    11 const int maxn = 25;
    12 int n, m, MOD;
    13 char s[maxn];
    14 int nxt[maxn];
    15 struct Matrix
    16 {
    17     int mat[maxn][maxn];
    18     Matrix() { mset(mat, 0); }
    19     Matrix operator * (const Matrix &AI) const
    20     {
    21         Matrix ret;
    22         REP(i, 0, m-1)
    23             REP(j, 0, m-1)
    24             {
    25                 ret.mat[i][j] = 0;
    26                 REP(k, 0, m-1) (ret.mat[i][j] += mat[i][k]*AI.mat[k][j]) %= MOD;
    27             }
    28         return ret;
    29     }
    30 }A, B;
    31 
    32 int main()
    33 {
    34     scanf("%d %d %d", &n, &m, &MOD);
    35     scanf("%s", s+1);
    36     int j = 0; nxt[1] = 0;
    37     REP(i, 2, m)
    38     {
    39         while (j > 0 && s[j+1] != s[i]) j = nxt[j];
    40         if (s[j+1] == s[i]) j ++;
    41         nxt[i] = j;
    42     }
    43     REP(i, 0, m-1)
    44         REP(j, 0, 9)
    45         {
    46             int t = i;
    47             while (t > 0 && s[t+1]-'0' != j) t = nxt[t];
    48             if (s[t+1]-'0' == j) t ++;
    49             if (t != m) B.mat[t][i] = (B.mat[t][i]+1)%MOD;
    50         }
    51     REP(i, 0, m-1) A.mat[i][i] = 1;
    52     while (n > 0)
    53     {
    54         if (n&1) A = A*B;
    55         B = B*B; 
    56         n >>= 1;
    57     }
    58     int ans = 0;
    59     REP(i, 0, m-1) ans = (ans+A.mat[i][0])%MOD;
    60     printf("%d
    ", ans);
    61     return 0;
    62 }
    View Code

     

     

     

     

  • 相关阅读:
    我的第一个shell 脚本
    ubuntu下配置java环境变量在root用户不生效
    ES6ES11易忘笔记
    UE4:Gameplay
    游戏服务器架构
    手柄陀螺仪、加速度计算
    UE4启动脚本(命令行参数)
    UE4:时间相关
    shell基础
    go Cobra命令行工具入门
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6697386.html
Copyright © 2020-2023  润新知