bzoj1009: [HNOI2008]GT考试

本文介绍了一种使用KMP算法优化的矩阵快速幂方法解决特定字符串匹配问题的思路。通过定义状态f[i][j]来表示前i位后j位与不吉利串前j位相同的方案数,并利用矩阵乘法进行快速转移,最终实现了高效求解。

思路:设f[i][j]表示前i位后j位与不吉利串前j位相同的方案数,然后f[i][j]+=f[i-1][k]*trans[k][j],trans[k][j]表示串s后k位与不吉利串前k位相同,添加一个字符后后j位与不吉利串前j位相同的方案数,显然这个矩阵是可以用kmp求的,然后因为只能由i转移到i+1,且转移矩阵是一定的,于是可以用矩阵乘法快速幂优化dp即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxm 25
 
int n,m,p;
int next[maxm];
char s[maxm];
 
struct matrix{
    int a[maxm][maxm];
    void clear(){memset(a,0,sizeof(a));}
    void initialize(){clear();for (int i=0;i<m;i++) a[i][i]=1;}
}trans;
 
void getnext(){
    int len=strlen(s+1);next[1]=0;
    for (int i=2,j=0;i<=len;i++){
        while (j&&s[j+1]!=s[i]) j=next[j];
        if (s[j+1]==s[i]) j++;
        next[i]=j;
    }
}
 
void gettrans(){
    for (int i=0;i<m;i++)
        for (int j=0;j<=9;j++){
            int tmp=i;
            while (tmp && (s[tmp+1]-'0')!=j) tmp=next[tmp];
            if ((s[tmp+1]-'0')==j) trans.a[i][tmp+1]++,trans.a[i][tmp+1]%=p;
            else trans.a[i][0]++,trans.a[i][0]%=p;
        }
}
 
matrix mul(matrix a,matrix b){
    matrix c;c.clear();
    for (int i=0;i<m;i++)
        for (int j=0;j<m;j++)
            for (int k=0;k<m;k++)
                c.a[i][k]=(c.a[i][k]+a.a[i][j]*b.a[j][k]%p)%p;
    return c;
}
 
matrix power(matrix a,int k){
    matrix x;x.initialize();
    for (;k;k>>=1,a=mul(a,a)) if (k&1) x=mul(x,a);
    return x;
}
 
int main(){
    scanf("%d%d%d",&n,&m,&p);
    scanf("%s",s+1);
    getnext();
    gettrans();
    matrix tmp=power(trans,n),ans;ans.clear(),ans.a[0][0]=1;int t=0;
    ans=mul(ans,tmp);
    for (int i=0;i<m;i++) t=(t+ans.a[0][i])%p;
    printf("%d\n",t);
    return 0;
}

 

转载于:https://www.cnblogs.com/DUXT/p/6007054.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值