P3193 [HNOI2008]GT考试 题解(kmp+矩阵快速幂)

题目链接

题目思路

\(dp[i][j]\)表示长度为\(i\)的字符串匹配长度为\(j\)的字符串

如果第\(i+1\)个字符等于\(s[j+1]\) 那么就转移到\(dp[i+1][j+1]\)

否则根据\(kmp\)那么此时\(j=nxt[j]\) 然后再递归判断

数据这么大要往矩阵快速幂的思路去思考

\(base.a[i][j]\) 表示有多少种方案数使得加一个字符使得匹配\(i\)个字符变为\(j\)个字符

那么\(ans.a[i][j]=\sum_{k=0}^{k=m-1}ans.a[i][k]\times base.a[k][j]\)

然后再使用矩阵快速幂加速

对于矩阵快速幂的理解

以我们把每一行\(ans[i][j]\)抽象成只有一行,列数为\(m-1\)\(F[i]\)

最后即为\(F[i]=F[i-1]*base^n\)

我感觉这个题目太多细节了

实在太妙了

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=20+5,inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m,k,mod;
char s[maxn];
int nxt[maxn];
struct matrix{
    ll a[maxn][maxn];
}base,ans,last;
matrix mul(matrix a,matrix b,int n){
    matrix temp;
    memset(temp.a,0,sizeof(temp.a)); //一定1要清空
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            for(int k=0;k<n;k++){
                temp.a[i][k]+=(a.a[i][j])*(b.a[j][k]);
                temp.a[i][k]%=mod;
            }
        }
    }
    return temp;
}
void qpow(ll n,ll b){
    while(b){
        if(b&1){
            ans=mul(ans,base,n);
        }
        base=mul(base,base,n);
        b=b>>1;
    }
}

void getnext(){
    for(int i=2,j=0;i<=m;i++){
        while(j&&s[j+1]!=s[i]){
            j=nxt[j];
        }
        if(s[j+1]==s[i]) j++;
        nxt[i]=j;
    }
}
void getbase(){
    for(int i=0;i<m;i++){ //现在匹配了i位
        for(int j=0;j<=9;j++){
            int x=i;
            while(x&&j!=s[x+1]-'0'){
                x=nxt[x];
            }
            if(j==s[x+1]-'0'){
                x++;
            }
            if(x!=m){
                base.a[i][x]=(base.a[i][x]+1)%mod;
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&mod);
    scanf("%s",s+1);
    getnext();
    getbase();
    for(int i=0;i<m;i++){
        ans.a[i][i]=1;
    }
    qpow(m,n);
    ll pr=0;
    last.a[0][0]=1;
    last=mul(last,ans,m);
    for(int i=0;i<m;i++){
        pr=(pr+last.a[0][i])%mod;
    }
    printf("%lld\n",pr);
    return 0;
}

不摆烂了,写题
原文地址:https://www.cnblogs.com/hunxuewangzi/p/15039574.html