• [BZOJ1009] [HNOI2008] GT考试 (KMP & dp & 矩阵乘法)


    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

    HINT

    Source

    Solution

      $f[i][j]$表示由$i$的数字构成的数串中与不吉利数字刚好匹配$j$位的方案数

      因为我们只需关心后$j$位是否被匹配,如果在不久的将来有一位失配,那么这一段字符就一定不是给定的数串

      可以看出来,由$f[i]$转移到$f[i+1]$时,需要借助$KMP$算出,具体方法就是枚举$0sim 9$,用$pi$数组算出匹配的位数$k$,$f[i+1][k]$+=$f[i][j]$

      注意到准考证号位数可以达到$10^9$妈蛋考试时号码都抄不完,$TLE/MLE$无疑

      由于每一次$f[i]$转移到$f[i+1]$时所有步骤是一样的,所以可以用一个矩阵,用乘法代替一次转移。这样就可以用快速幂优化转移啦

      构造矩阵暴力即可,注意$f[i][m]$的特殊性,它每次只向$f[i+1][m]$转移。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int mod, pi[25];
     4 struct matrix
     5 {
     6     int a[25][25], n, m;
     7  
     8     matrix() {}
     9  
    10     matrix(int x, int y)
    11     {
    12         n = x, m = y;
    13         memset(a, 0, sizeof(a));
    14     }
    15  
    16     matrix operator* (matrix rhs)
    17     {
    18         matrix ans(n, rhs.m);
    19         for(int i = 0; i < n; ++i)
    20             for(int j = 0; j < rhs.m; ++j)
    21                 for(int k = 0; k < m; ++k)
    22                     ans.a[i][j] = (ans.a[i][j] + a[i][k] * rhs.a[k][j]) % mod;
    23         return ans;
    24     }
    25  
    26     matrix operator^ (int rhs)
    27     {
    28         matrix ans(n, n), bs = *this;
    29         for(int i = 0; i < n; ++i)
    30             ans.a[i][i] = 1;
    31         for(; rhs; rhs >>= 1, bs = bs * bs)
    32             if(rhs & 1) ans = ans * bs;
    33         return ans;
    34     }
    35 };
    36 char s[25];
    37  
    38 void getpi(int m)
    39 {
    40     int j = 0;
    41     for(int i = 2; i <= m; ++i)
    42     {
    43         while(j && s[i] != s[j + 1])
    44             j = pi[j];
    45         pi[i] = s[i] == s[j + 1] ? ++j : j;
    46     }
    47 }
    48  
    49 int main()
    50 {
    51     int n, m, ans, bs = 10;
    52     cin >> n >> m >> mod >> s + 1;
    53     getpi(m);
    54     matrix f(1, m + 1), w(m + 1, m + 1);
    55     f.a[0][0] = 1, w.a[m][m] = 10;
    56     for(int i = 0; i < m; ++i)
    57         for(int j = 0; j < 10; ++j)
    58         {
    59             int k = i;
    60             while(k && j != s[k + 1] - 48)
    61                 k = pi[k];
    62             if(j == s[k + 1] - 48) ++k;
    63             ++w.a[i][k];
    64         }
    65     f = f * (w ^ n);
    66     for(ans = 1; n; n >>= 1, bs = (bs * bs) % mod)
    67         if(n & 1) ans = (ans * bs) % mod;
    68     cout << (ans - f.a[0][m] + mod) % mod << endl;
    69     return 0;
    70 }
    View Code
  • 相关阅读:
    DIV+CSS笔记(二)
    DIV+CSS笔记(一)
    HTML基础笔记
    面向对象—封装—重载
    面向对象—封装
    面向对象—封装—people
    面向对象—封装—三角形
    权限修饰符—1
    权限修饰符—2(Father、Son)
    权限修饰符—3
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5616651.html
Copyright © 2020-2023  润新知