洛谷P3193 [HNOI2008] GT考试 题解 KMP+矩阵乘法加速DP

题目链接:https://www.luogu.com.cn/problem/P3193

解题思路:

建立完 KMP 的 nxt 数组之后(其实也可以建状态机,但是 \(m \le 20\) 所以建 状态机 并不是必要的),构造一个转移矩阵。然后矩阵乘法优化,就能够得到答案了。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 25;

ll mod;

struct Matrix {
    int n, m;
    ll a[maxn][maxn];

    void init(int _n, int _m) {
        n = _n;
        m = _m;
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= m; j++)
                a[i][j] = 0;
    }

    Matrix operator * (const Matrix &b) const {
        Matrix res;
        res.init(n, b.m);
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= m; j++)
                for (int k = 0; k <= b.m; k++)
                    res.a[i][k] += a[i][j] * b.a[j][k],
                    res.a[i][k] %= mod;
        return res;
    }

    Matrix operator ^ (int k) const {
        Matrix res, t;
        res.init(n, n);
        for (int i = 0; i <= n; i++)
            res.a[i][i] = 1;
        t.init(n, n);
        memcpy(t.a, a, sizeof a);
        for (; k; k >>= 1, t = t * t)
            if (k & 1)
                res = res * t;
        return res;
    }

} A, B;

int nxt[maxn];
char s[maxn];
int n, m;

void cal_nxt() {
    nxt[1] = 0;
    for (int i = 2, j = 0; i <= m; i++) {
        while (j && s[j+1] != s[i]) j = nxt[j];
        if (s[j+1] == s[i]) j++;
        nxt[i] = j;
    }
}

int main() {
    cin >> n >> m >> mod >> s + 1;
    cal_nxt();
    A.init(0, m);
    A.a[0][0] = 1;
    B.init(m, m);
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < 10; j++) {
            int k = i;
            while (k && s[k+1] != '0' + j)
                k = nxt[k];
            if (s[k+1] == '0' + j) k++;
            if (k < m)
                B.a[i][k]++;
        }
    }
    A = A * (B ^ n);
    ll ans = 0;
    for (int i = 0; i < m; i++)
        (ans += A.a[0][i]) %= mod;
    cout << ans << endl;
    return 0;
}

posted @ 2026-05-21 20:53  quanjun  阅读(11)  评论(0)    收藏  举报