BZOJ1009: [HNOI2008]GT考试 (矩阵快速幂 + DP)

题意:求一个长度为n的数字字符串 (n <= 1e9)

   不出现子串s的方案数

题解:用f i,j表示长度为i匹配到在子串j的答案

   用kmp的失配函数预处理一下 然后这个转移每一个都是一样的 所以可以用矩阵加速

 

#include <bits/stdc++.h>
using namespace std;

int n, m, mod;
char s[25];
int fail[25];

struct node {
    int c[25][25];
}a, re;

node mul(node x, node y) {
    node res;
    memset(res.c, 0, sizeof(res.c));

    for(int i = 0; i < m; i++)
    for(int j = 0; j < m; j++)
    for(int k = 0; k < m; k++)
        res.c[i][j] = (res.c[i][j] + x.c[i][k] * y.c[k][j] % mod) % mod;
    return res;
}

node pow_mod(node x, int y) {
    node res;
    memset(res.c, 0, sizeof(res.c));
    for(int i = 0; i < m; i++) res.c[i][i] = 1;

    while(y) {
        if(y & 1) res = mul(res, x);
        x = mul(x, x);
        y >>= 1;
    }
    return res;
}

int main() {
    scanf("%d%d%d", &n, &m, &mod);
    scanf("%s", s + 1);

    fail[1] = fail[2] = 0;
    for(int i = 2; i <= m; i++) {
        int j = fail[i - 1];
        while(j && s[i] != s[j + 1]) j = fail[j];
        fail[i] = s[i] == s[j + 1] ? j + 1 : 0;
    }

    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 = fail[k];
            if(s[k + 1] - '0' == j) k++;
            if(k != m) a.c[i][k] = (a.c[i][k] + 1) % mod;
        }
    }

    re = pow_mod(a, n);
    int ans = 0;
    for(int i = 0; i < m; i++) ans = (ans + re.c[0][i]) % mod;
    
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2019-06-25 12:12  lwqq3  阅读(214)  评论(0编辑  收藏  举报