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 25
using 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);
}

 

posted @ 2014-09-20 16:31  handsomeJian  阅读(161)  评论(0编辑  收藏  举报