Description
阿申准备报名参加 GT 考试,准考证号为 $N$ 位数 $X_1,X_2…X_n(0\le X_i\le9)$,他不希望准考证号上出现不吉利的数字。 他的不吉利数字 $A_1,A_2…A_m(0\le A_i\le 9)A_1,A_2…A_m(0≤A_i≤9)$ 有 $M$ 位,不出现是指 $X_1,X_2…X_n$ 中没有恰好一段等于 $A_1,A_2…A_m$,$A_1$ 和 $X_1$ 可以为 $0$。
Solution
我过的挺玄学。
先考虑 DP。$f_{i,j}$ 表示准考证前 $i$ 位数未出现不吉利数字,且当前已经与不吉利数字匹配 $j$ 位(即后 $j$ 位与不吉利数字前 $j$ 位相同)的方案数。
一看就是个 KMP,构建出 $\text{fail}$ 数组,又发现 $n\leq10^9$,往矩阵快速幂的方面去靠一靠。
发现当已经匹配 $p$ 位时,下一位有 $9$ 种选择,于是枚举这九种选择,利用 $\text{fail}$ 数组,可以快速转移到选择之后匹配到第几位。
于是发现这是个刷表转移,把这个刷表转成矩阵就成为了初始矩阵。
于是快速幂一下就做完了。
但要注意构造矩阵时的细节。
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using std::cout;
using std::endl;
const int maxn = 110, maxm = 22;
int mod;
int n, m, k;
struct matrix
{
int n, m;
long long a[maxn][maxn];
matrix() : n(0), m(0) { memset(a, 0, sizeof(a)); }
matrix(int _n, int _m) : n(_n), m(_m) { memset(a, 0, sizeof(a)); }
matrix(int _n, int _m, long long _a[maxn][maxn]) : n(_n), m(_m)
{
for (int i = 1; i <= _n; i++)
for (int j = 1; j <= _m; j++)
a[i][j] = _a[i][j];
}
matrix operator*(const matrix b)
{
matrix res(n, b.m);
for (int i = 1; i <= n; i++)
for (int k = 1; k <= m; k++)
for (int j = 1; j <= b.m; j++)
res.a[i][j] += a[i][k] * b.a[k][j] % mod, res.a[i][j] %= mod;
return res;
}
void print()
{
for (int i = 1; i <= n; i++, puts(""))
for (int j = 1; j <= m; j++)
printf("%lld ", a[i][j]);
}
matrix qpow(int x)
{
return qpow(*this, x);
}
matrix qpow(matrix a, int x)
{
matrix res = a;
x--;
for (; x; x >>= 1)
{
if (x & 1)
res = res * a;
a = a * a;
}
return res;
}
} base;
char s[maxm];
int fail[maxm];
int a[maxm][maxm];
void get_fail()
{
for (int i = 2, j = 0; i <= m; i++)
{
while (j && s[j + 1] != s[i])
j = fail[j];
if (s[j + 1] == s[i])
j++;
fail[i] = j;
}
}
void init()
{
for (int i = 1; i <= m; i++)
{
for (char num = '0'; num <= '9'; num++)
{
int j = i - 1;
while (j && s[j + 1] != num)
j = fail[j];
if (s[j + 1] == num)
j++;
if (j != m)
base.a[i][j + 1]++;
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &mod);
scanf("%s", s + 1);
get_fail();
init();
base.n = m, base.m = m;
//base.print();
matrix ans = base.qpow(n);
long long res = 0;
//ans.print();
for (int i = 1; i <= m; i++)
res += ans.a[1][i], res %= mod;
printf("%lld\n", res);
}