1009: [HNOI2008]GT考试

1009: [HNOI2008]GT考试

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

分析:

  f[i][j]表示第一个字符串到i,与第二个匹配了j个的方案数。新加一个字符,如果第一个字符串仍与第二个一样,那么转移到f[i+1][j+1],否则,转移到f[i+1[k],k是不确定的。预处理g[i][j]表示两个字符串匹配了i,然后增加一个字符后,匹配的位数变成j后的方案数。

  那么有转移方程:$dp[i][j]=\sum_{0<=k<=m-1}dp[i-1][k] \times g[k][j]$

  然后发现n特别大,但是每个i转移只有20-1(等于m了,就不用记录了)个,所以可以矩阵快速幂。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 100;

int p[N], g[N][N];
char s[N];
int n, m, mod;

struct Matrix{
    int a[N][N];
    void init() {
        for (int i=0; i<m; ++i) a[i][i] = 1;
    }
    void Clear() {
        memset(a, 0, sizeof(a));
    }
}A;
Matrix mul(Matrix A, Matrix B) {
    Matrix C; C.Clear();
    for (int k=0; k<m; ++k)
        for (int i=0; i<m; ++i)
            for (int j=0; j<m; ++j)
                C.a[i][j] = (C.a[i][j] + 1ll * A.a[i][k] * B.a[k][j] % mod) % mod;
    return C;
}
Matrix ksm(Matrix a,int b) {
    Matrix res; res.Clear(); res.init();
    while (b) {
        if (b & 1) res = mul(res, a);
        a = mul(a, a);
        b >>= 1;
    }
    return res;
}
void KMP() {
    p[1] = 0;
    for (int i=2; i<=m; ++i) {
        int j = p[i - 1];
        while (j && s[j + 1] != s[i]) j = p[j];
        if (s[j + 1] == s[i]) j ++;
        p[i] = j;
    }
    for (int i=0; i<=m; ++i) {
        for (int j='0'; j<='9'; ++j) {
            int k = i;
            while (k && s[k + 1] != j) k = p[k];
            if (s[k + 1] == j) g[i][k + 1] ++;
            else g[i][0] ++;
        }
    }
}
int main() {
    n = read(), m = read(), mod = read();
    scanf("%s",s+1);
    KMP();
    for (int i=0; i<=m; ++i)
        for (int j=0; j<=m; ++j)
            A.a[i][j] = g[i][j];
    A = ksm(A, n);
    int Ans = 0;
    for (int i=0; i<m; ++i)
        Ans = (Ans + A.a[0][i]) % mod;
    cout << Ans;
    return 0;
}
posted @ 2018-09-13 21:33  MJT12044  阅读(172)  评论(0编辑  收藏  举报