• #KMP,矩阵乘法#洛谷 3193 [HNOI2008]GT考试


    题目

    给定(n,m,K)和一个长度为(m)的数(x)
    问有多少个(n)位数满足任意一段不与(x)完全相同,可含前导0
    (nleq 10^9,mleq 20)


    分析

    (dp[i][j])表示前(i)个数位匹配到(x)的第(j)位的方案数,
    可以发现加入一个新的字母不一定重新开始匹配,所以需要求出最长公共前后缀,
    用KMP实现,至于(nleq 10^9)可以用矩阵乘法维护转移即可


    代码

    #include <cstdio>
    #include <cstring>
    #define rr register
    using namespace std;
    struct maix{int p[20][20];}A,ANS;
    int n,m,mod,fail[21],ans; char s[21];
    inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline maix mul(maix A,maix B){
    	rr maix C;
    	memset(C.p,0,sizeof(C.p));
    	for (rr int i=0;i<m;++i)
    	for (rr int j=0;j<m;++j)
    	for (rr int k=0;k<m;++k)
    	    C.p[i][j]=mo(C.p[i][j],A.p[i][k]*B.p[k][j]%mod);
    	return C;
    }
    signed main(){
    	scanf("%d%d%d%s",&n,&m,&mod,s+1);
    	for (rr int i=2,j=0;i<=m;++i){
    		while (j&&s[j+1]!=s[i]) j=fail[j];
    		fail[i]=(j+=(s[j+1]==s[i]));
    	}
    	for (rr int i=0;i<m;++i)
    	for (rr int P=48;P<=57;++P){
    		rr int j=i;
    		while (j&&s[j+1]!=P) j=fail[j];
    		j+=(s[j+1]==P);
    		if (j!=m) ++A.p[i][j];
    	}
    	for (rr int i=0;i<m;++i) ANS.p[i][i]=1;
    	for (;n;n>>=1,A=mul(A,A))
    	    if (n&1) ANS=mul(ANS,A);
    	for (rr int i=0;i<m;++i) ans=mo(ans,ANS.p[0][i]);
    	return !printf("%d",ans);
    }
    
  • 相关阅读:
    深入解析MySQL分区(Partition)功能
    使用mysqlreplicate命令快速搭建 Mysql 主从复制
    MySQL优化/面试,看这一篇就够了
    Nginx+Keepalived高可用集群
    高并发核心技术
    Redis详解
    memcached 常用命令及使用说明
    MemCached详解
    音频和视频
    frameset 和iframe框架标签
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15178805.html
Copyright © 2020-2023  润新知