BZOJ 1009 GT考试 (AC自动机 + 矩阵乘法加速dp)

题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=1009

题意:

准考证号为\(n\)位数\(X_1X_2....X_n(0<=X_i<=9)\),你不希望准考证号上出现不吉利的数字。

你的不吉利数学\(A_1A_2...A_m(0<=A_i<=9)\)\(m\)位,不出现是指\(X_1X_2...X_n\) 中没有恰好一段等于\(A_1A_2...A_m\). A_1$ 和 \(X_1\)可以为\(0\)

问你不出现不吉利数字的号码有多少种,输出模\(mod\)取余的结果。

\(n<=10^9,M<=20,mod<=1000\)

题解:

对于这种间接的多模式匹配字符串+计数问题,我们可以用\(AC\)自动机+\(dp\)
\(dp[i][j]\)表示串长为 \(i\) , 匹配到了 \(AC\) 自动机的节点 \(j\),并且从来没有出现过完整的不吉利号码的方案数。
容易知道,\(dp\) 形式就是这样:

  dp[0][0] = 1;
  for(int i = 1; i <= n; i++) {
    for(int j = 0; j <= sz; j++) {
      for(int k = 0; k <= 9; k++) {
        int v = ch[j][k];
        if(End[v] == 0) {
          dp[i][v] += dp[i - 1][j];
          dp[i][v] %= mod;
        }
      }
    }
  }
  int res = 0;
  for(int i = 0; i <= sz; i++) {
    res += dp[n][i];
    res %= mod;
  }
  std::cout << "res = " << res << '\n';

但是\(N<=10^9\),显然复杂度会爆炸。
所以可以用矩阵快速幂来优化加速\(dp\)
初始化矩阵\(tmp = [1,0,0]\),意思和\(dp[0][0] = 1\)的初始化一样。
\(x\) 节点与\(x\)的所有儿子节点\(son\)在转移矩阵\(a\)\(a[x][son]+=1\)
这样在矩阵乘法的转移时,可以把父亲的状态装一到儿子。
最后答案即为\(tmp * a ^ n\)

猜你喜欢

转载自www.cnblogs.com/LzyRapx/p/9141874.html