[HNOI2008] GT考试

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=1009

[算法]

         首先用kmp预处理最长的后缀 = 前缀

         然后 , 用Fi,j表示前i位 , 匹配j位的方案数

         矩阵优化即可

         时间复杂度 : O(M ^ 3logN)

[代码]

        

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

int n , m , P;
int nxt[N];
int a[N][N] , b[N][N];
char s[N];

template <typename T> inline void update(T &x , T y)
{
    x += y;
    x %= P;
}
inline void multipy(int a[N][N] , int b[N][N])
{
    static int ret[N][N];
    memset(ret , 0 , sizeof(ret));
    for (int i = 0; i < m; i++)    
    {
        for (int j = 0; j < m; j++)
        {
            for (int k = 0; k < m; k++)
            {
                ret[i][j] = (ret[i][j] + 1LL * a[i][k] * b[k][j] % P) % P;
            }
        }
    }
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < m; j++)
        {
            a[i][j] = ret[i][j];
        }
    }
}

int main()
{
    
    scanf("%d%d%d" , &n , &m , &P);
    scanf("%s" , s + 1);
    nxt[1] = 0;
    for (int i = 2; i <= m; i++)
    {
        int tmp = nxt[i - 1];
        while (tmp > 0 && s[tmp + 1] != s[i]) tmp = nxt[tmp];
        if (s[tmp + 1] == s[i]) ++tmp;
        nxt[i] = tmp;    
    }
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j <= 9; j++)
        {
            int tmp = i;
            while (tmp > 0 && s[tmp + 1] - '0' != j) tmp = nxt[tmp];
            if (s[tmp + 1] - '0' == j) ++tmp;
            if (tmp != m) update(b[tmp][i] , 1);     
        }    
    }
    for (int i = 0; i < m; i++) a[i][i] = 1;
    while (n > 0)
    {
        if (n & 1) multipy(a , b);
        multipy(b , b);
        n >>= 1;
    }
    int ans = 0;
    for (int i = 0; i < m; i++) update(ans , a[i][0]);
    printf("%d\n" , ans);
    
    return 0;
    
}

 

posted @ 2018-12-06 19:42  evenbao  阅读(151)  评论(0编辑  收藏  举报