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

    Description

    求有多少个长度为n的0-9的数字串不包含一个给定的长度为m的数字串。

    Solution

    在kmp自动机上dp

    40pts kmp + dp

    考虑(dp),设(f_{i,j})表示前(i)个字符,匹配到给定串的第(j)位的方案数

    转移时枚举下一位放什么字符,然后用(kmp)处理出会匹配到哪一位,然后从(f_{i,j})转移到(f_{i,nxt})。需要注意的是,如果匹配到的下一位为(m),那么不需要进行转移。

    最终答案为(sum limits_{i=0}^{m-1} f[n][i])

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    const int _ = 20 + 10;
    const int __ = 1e6 + 10;
    int N, M, mod, nxt[_];
    char s[_];
    int f[__][_];
    
    inline void kmp() {
      nxt[1] = 0;
      for (int i = 2, j = 0; i <= M; ++i) {
        while (j > 0 && s[i] != s[j + 1]) j = nxt[j];
        if (s[i] == s[j + 1]) ++j;
        nxt[i] = j;
      }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("GT.in", "r", stdin);
      freopen("GT.out", "w", stdout);
    #endif
      scanf("%d%d%d", &N, &M, &mod);
      scanf("%s", s + 1);
      kmp();
    
      f[0][0] = 1;
      for (int i = 0; i < N; ++i) {
        for (int j = 0; j <= M; ++j) {
          for (int k = 0; k <= 9; ++k) {
            int tmp = j;
            while (tmp > 0 && k != s[tmp + 1] - '0') tmp = nxt[tmp];
            if (k == s[tmp + 1] - '0') ++tmp;
            if (tmp < M) f[i + 1][tmp] = (f[i + 1][tmp] + f[i][j]) % mod;
          }
        }
      }
    
      int ans = 0;
      for (int i = 0; i < M; ++i) ans = (ans + f[N][i]) % mod;
      printf("%d
    ", ans);
      return 0;
    }
    

    100pts 矩阵加速转移

    实际上,并不需要每次枚举字母,我们可以预处理出从一个匹配长度加一个字符变成另一个匹配长度的方案数,设为(g_{i,j})

    [f_{i,j}=sum limits_{k=0}^{m-1} f_{i-1,k} imes g_{k,j} ]

    这个式子显然是可以矩阵优化的,于是矩阵快速幂之后,就可以通过本题了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    const int _ = 23;
    int N, M, mod, nxt[_], cnt[_][_];
    char s[_];
    
    struct Matrix {
      int A[_][_];
      Matrix() { memset(A, 0, sizeof(A)); }
      Matrix operator*(const Matrix &b) const {
        Matrix c;
        memset(c.A, 0, sizeof(c.A));
        for (int i = 0; i < M; ++i)
          for (int j = 0; j < M; ++j)
            for (int k = 0; k < M; ++k)
              c.A[i][j] = (c.A[i][j] + A[i][k] * b.A[k][j] % mod) % mod;
        return c;
      }
    } F, G;
    
    inline void kmp() {
      nxt[1] = 0;
      for (int i = 2, j = 0; i <= M; ++i) {
        while (j > 0 && s[i] != s[j + 1]) j = nxt[j];
        if (s[i] == s[j + 1]) ++j;
        nxt[i] = j;
      }
      for (int i = 0; i < M; ++i) {
        for (int j = '0'; j <= '9'; ++j) {
          int k = i;
          while (k > 0 && j != s[k + 1]) k = nxt[k];
          if (j == s[k + 1]) ++k;
          if (k < M) ++cnt[i][k];
        }
      }
    }
    
    Matrix ksm(Matrix a, int b) {
      Matrix ret;
      for (int i = 0; i < M; ++i) ret.A[i][i] = 1;
      for (; b; b >>= 1) {
        if (b & 1) ret = ret * a;
        a = a * a;
      }
      return ret;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("GT.in", "r", stdin);
      freopen("GT.out", "w", stdout);
    #endif
      scanf("%d%d%d", &N, &M, &mod);
      scanf("%s", s + 1);
      kmp();
    
      for (int i = 0; i < M; ++i)
        for (int j = 0; j < M; ++j) G.A[i][j] = cnt[i][j];
      F.A[0][0] = 1;
      G = ksm(G, N);
      F = F * G;
      int ans = 0;
      for (int i = 0; i < M; ++i) ans = (ans + F.A[0][i]) % mod;
      printf("%d
    ", ans);
      return 0;
    }
    
  • 相关阅读:
    FZU 1759 欧拉函数 降幂公式
    51nod 1126 矩阵快速幂 水
    Codeforces Round #325 (Div. 2) D bfs
    Codeforces Round #379 (Div. 2) A B C D 水 二分 模拟
    Codeforces Round #284 (Div. 2)A B C 模拟 数学
    CentOS 7 rsync
    子进程 已安装 pre-removal 脚本 返回了错误号 1或2 与 子进程 已安装 post-installation 脚本 返回了错误号 1或2
    VirtualBox
    Eclipse 安装 HDFS 插件
    docker log 文件 清理
  • 原文地址:https://www.cnblogs.com/newbielyx/p/12145268.html
Copyright © 2011-2022 走看看