首页 > 代码库 > bzoj 1009:[HNOI2008]GT考试

bzoj 1009:[HNOI2008]GT考试

     这道题机房n多人好久之前就A了…… 我到现在才做出来……

     一看就是DP+矩阵乘法,但是一开始递推式推错了…… 正确的递推式应该是二维的……

  f[i][j] 表示第准考证到第 i 位匹配了 j 位的方案数

  f[i][j] = f[i][j-1] + f[i][k]  第k位可以转移到第 j 位

     这就需要枚举 当前位是什么, 同是还需要求一个关于m 的KMP 就可以了

  上代码:

#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>#define M 25using namespace std;int n, m;long long f[M] = {0}, yu;long long a[M][M] = {0}, b[M][M] = {0}, c[M][M];int next[M] = {0};char s[M];void make_next(){    int i = 0, j = -1;    next[0] = -1;    while (i < m-1)        if (j == -1 || s[i] == s[j])        {            i++; j++;            next[i] = j;        }        else j = next[j];}void cheng(){    for (int i = 0; i < m; ++i)        for (int j = 0; j <= m; ++j)            c[i][j] = 0;    for (int i = 0; i < m; ++i)    for (int j = 0; j < m; ++j)    for (int k = 0; k < m; ++k)        c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % yu;    swap(c, b);}void fan(){    for (int i = 0; i < m; ++i)        for (int j = 0; j <= m; ++j)            c[i][j] = 0;    for (int i = 0; i < m; ++i)    for (int j = 0; j < m; ++j)    for (int k = 0; k < m; ++k)        c[i][j] = (c[i][j] + a[i][k] * a[k][j]) % yu;    swap(c, a);}void mi(int n){    for (int i = 0; i < m; ++i)            b[i][i] = 1;    while (n)    {        if (n & 1) cheng();        n >>= 1;        fan();    }    swap(a, b);}int main(){    scanf("%d%d%I64d", &n, &m, &yu);    scanf("%s", s);    make_next();    f[0] = 1;    for (int i = 0; i < m; ++i) //已经匹配 i 位 正在匹配第 i+1 位     {        for (int j = 0; j <= 9; ++j) // 第 i+1 位是 j             if (j == s[i]) a[i+1][i] ++; // success            else // fail  find the last can pipei            {                int x = next[i];                while (x != -1 && s[x] != j)                    x = next[x];                a[x+1][i] ++;            }    }    mi(n);    long long ans = 0;    for (int i = 0; i < m; ++i)    {        long long zan = 0;        for (int j = 0; j < m; ++j)            zan = (zan + f[j] * a[i][j]) % yu;        ans = (ans + zan) % yu;    }    printf("%I64d\n", ans);}

 

bzoj 1009:[HNOI2008]GT考试