[HNOI2008] GT exam - KMP + matrix fast power

Description

Seeking the number of length n, 0-9 digit string does not contain a numeric string given length m.

Solution

dp on kmp automaton

40pts kmp + dp

Consider \ (DP \) , provided \ (f_ {i, j} \) representing the forward (I \) \ characters given to the first matching string to \ (J \) Program Number of bits

A character at what to put Enumeration transfer, then \ (KMP \) process where the match will be one, and the \ (f_ {i, j} \) was transferred to \ (f_ {i, nxt} \ ) . It should be noted that, if the match to the next bit is \ (m \) , then no transfer.

The final answer is \ (\ 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\n", ans);
  return 0;
}

100pts accelerate the transfer matrix

In fact, does not need to enumerate each letter, we can pre-program another number into the match length from a length plus a matching character set \ (g_ {i, j} \)

Then
\ [f_ {i, j}
= \ sum \ limits_ {k = 0} ^ {m-1} f_ {i-1, k} \ times g_ {k, j} \] This matrix equation can be clearly optimization, so after a quick power matrix, can, through this question of.

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\n", ans);
  return 0;
}

Guess you like

Origin www.cnblogs.com/newbielyx/p/12145268.html