Description

阿申准备报名参加 GT 考试, 准考证号为 \(n\) 位数 \(x_1 x_2 \ldots x_n (0 \leq x_i \leq 9)\), 他不希望准考证号上出现不吉利的数字.

他的不吉利数字 $a_1 a_2 a_m (0 a_i 9) 有 \(m\) 位, 不出现是指 \(x_1 x_2 \ldots x_n\) 中没有恰好一段等于 \(a_1 a_2 \ldots a_m\).\(a_1\)\(x_1\) 可以为 \(0\).

Input

第一行输入 \(n, m, k\). 接下来一行输入 \(m\) 位的数.

Output

阿申想知道不出现不吉利数字的号码有多少种, 输出模 \(k\) 取余的结果.

Sample Input

4 3 100
111

Sample Output

81

Data Range

对于所有的数据, 满足:\(n \leq 10^9, m \leq 20, k \leq 1000\)

Explanation

膜一发黄学长题解:

矩阵乘法的题题解写起来都十分麻烦......

而且很多东西只能意会......

\(f[i, j]\) 表示前 \(i\) 个准考证号匹配到不吉利串第 \(j\) 个的方案

然后你需要把一个答案矩阵 \(f[i, j]\) 转移到 \(f[i+1, j]\)

举个例子, 样例, 比如当前匹配到了第 \(2\) 位, 也就是说前 \(i\) 位的结尾是 \(11\)

对于第 \(i+1\) 个字符, 如果是 \(1\) 的话, 接着匹配到不吉利串第 \(3\) 位, 不是 \(1\) 的话 就匹配到第 \(0\) 位了

也就是说前 \(i\) 位匹配到了不吉利串 \(j\) 位, 加入 \(i+1\) 这个字符, 有不同情况, 有一些会转移到 \(j+1\), 一些会转移到其他的, 写成一些形如 \(f[i+1, k] += f[i, j]\) 的式子......

\[f[i+1, 3] += f[i, 2]\]

\[f[i+1, 0] += f[i, 2]\]

即枚举 \(i+1\) 可能出现的字符, 然后看 \(n\)\(f[i, j]\) 分别转移到哪去, 就在转移矩阵 的这个转移路径上+1

按照这个思路用 kmp 写出转移矩阵, 事实上暴力应该就行了

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#define rep(_var,_begin,_end) for(int _var=_begin;_var<=_end;_var++)
using namespace std;
typedef long long lli;
const int maxm = 25;
lli modr;

struct Matrix {
    int sz; lli dat[maxm][maxm];
    Matrix(void) { sz = 0; memset(dat, 0, sizeof(dat)); }
    Matrix(int sz_) { sz = sz_; memset(dat, 0, sizeof(dat)); }
};
Matrix operator * (Matrix a, Matrix b)
{
    Matrix c(a.sz);
    rep(i, 0, a.sz) rep(j, 0, b.sz) {
        c.dat[i][j] = 0;
        rep(k, 0, a.sz)
            c.dat[i][j] = (c.dat[i][j] +
                a.dat[i][k] * b.dat[k][j]) % modr;
    }
    return c;
}
Matrix operator ^ (Matrix b, lli pw)
{
    Matrix a(b.sz);
    for (int i = 0; i < a.sz; i++)
        a.dat[i][i] = 1;
    while (pw > 0) {
        if (pw & 1 == 1)
            a = a * b;
        b = b * b;
        pw >>= 1;
    }
    return a;
}

lli n; int m;
char str[maxm];
int pre[maxm]; // KMP-Purposes only

int main(int argc, char** argv)
{
    scanf("%lld%d%lld", &n, &m, &modr);
    scanf("%s", str + 1);
    for (int i = 1; i <= m; i++)
        str[i] -= '0';
    // Preprocessing prefix function with KMP algorithm
    for (int i = 2, j = 0; i <= m; i++) {
        while (j > 0 && str[j + 1] != str[i])
            j = pre[j];
        if (str[j + 1] == str[i])
            j++;
        pre[i] = j;
    }
    // Constructing matrix of migration
    Matrix mov(m);
    for (int i = 0; i < m; i++)
        for (int j = 0; j <= 9; j++) {
            int t = i;
            while (t > 0 && str[t + 1] != j)
                t = pre[t];
            if (str[t + 1] == j)
                t++;
            if (t != m)
                mov.dat[t][i] = (mov.dat[t][i] + 1) % modr;
        }
    // Getting result.
    Matrix mat = mov ^ n;
    int sum = 0;
    for (int i = 0; i < m; i++)
        sum = (sum + mat.dat[i][0]) % modr;
    printf("%d\n", sum);
    return 0;
}