#P0787. [HNOI2008] GT考试

题目描述

阿申准备报名参加 GT 考试,准考证号为 NN 位数X_1,X_2…X_n(0\le X_i\le9)X1​,X2​…Xn​(0≤Xi​≤9),他不希望准考证号上出现不吉利的数字。 他的不吉利数字A_1,A_2…A_m(0\le A_i\le 9)A1​,A2​…Am​(0≤Ai​≤9) 有 MM 位,不出现是指 X_1,X_2…X_nX1​,X2​…Xn​ 中没有恰好一段等于 A_1,A_2…A_mA1​,A2​…Am​,A_1A1​ 和X_1X1​ 可以为 00

输入格式

第一行输入N,M,K.接下来一行输入M位的数。

输出格式

阿申想知道不出现不吉利数字的号码有多少种,输出模 KK 取余的结果。

输入数据 1

4 3 100
111

Copy

输出数据 1

81

Copy

提示

N\leq10^9,M\leq20,K\leq1000N≤109,M≤20,K≤1000

代码:

#include 
#include 
using namespace std;

const int N = 1e9 + 10, M = 30;
int n, m, P;
char s[M];
int ne[M], c[M][M], f[M][M];

void mult(int a[][M], int b[][M]) {
  static int res[M][M];
  memset(res, 0, sizeof res);
  for (int i = 0; i < m; i++)
    for (int j = 0; j < m; j++)
      for (int k = 0; k < m; k++)
        // 注意这里的乘法要写为b * a,因为我们要求mult(f, c),实际上是矩阵c乘以矩阵f
        res[i][j] = (res[i][j] + b[i][k] * a[k][j]) % P;
  for (int i = 0; i < m; i++)
    for (int j = 0; j < m; j++) a[i][j] = res[i][j];
}

void fast_pow(int n) {
  // 注意这里我们将f向量横向扩展为了f矩阵,最终答案只需考虑第0列即可
  f[0][0] = 1;
  while (n) {
    if (n & 1) mult(f, c);
    n >>= 1;
    mult(c, c);
  }
}

int main() {
  scanf("%d%d%d", &n, &m, &P);
  scanf("%s", s + 1);
  for (int i = 2, j = 0; i <= m; i++) {
    while (j && s[i] != s[j + 1]) j = ne[j];
    if (s[i] == s[j + 1]) j++;
    ne[i] = j;
  }

  for (int j = 0; j < m; j++)
    for (char ch = '0'; ch <= '9'; ch++) {
      int k = j;
      while (k && s[k + 1] != ch) k = ne[k];
      if (s[k + 1] == ch) k++;
      if (k < m) c[k][j]++;
    }

  fast_pow(n);
  int res = 0;
  for (int i = 0; i < m; i++) res = (res + f[i][0]) % P;
  printf("%d\n", res);
}

你可能感兴趣的:(算法,c++)