zoukankan      html  css  js  c++  java
  • [HNOI2008]GT考试 题解

    这题比较难搞。考虑设计状态:(f_{i,j}) 表示当前考虑到 (X_i) 位,且 (X) 的后 (j) 位刚好与 (A) 列匹配时的方案数。最终答案为 (sum_{i=0}^{m-1}f_{n,i})
    接下来考虑如何转移,如果我们以外层位置作为状态,则必然是从 (f_{i-1}) 转移到 (f_i) 来,我们需要枚举最后一位进行转移,但枚举最后一位对内层循环却不太好控制,因为我们不太清楚它的匹配长度到底是多少。所以转化思路,另设 (g_{i,j}) 表示在 (X) 的后 (i) 位与 (A) 列匹配的情况下,有多少种加数字的方法使得匹配长度变为 (j),这么做可以使 (g) 只与 (A) 列有关,能够预处理出来。
    那么转移方程:

    [f_{i,j}=sum_{k=0}^{m-1}f_{i-1,k}g_{k,j} ]

    由于 (n) 比较大,又发现这个式子长得很像矩阵乘法的式子,故可以快速幂递推。即

    [F_i=[f_{i,0} f_{i,1} dots f_{i,m-1}]=F_{i-1}G,F_n=F_0G^n ]

    代码还是挺好写的

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=25;
    int n,m,djq,nxt[N],g[N][N],f[N][N],res[N][N],ans;
    char s[N];
    
    void mul(int a[N][N],int b[N][N])
    {
    	static int c[N][N];
    	memset(c,0,sizeof(c));
    	for(int i=0;i<m;++i)
    		for(int j=0;j<m;++j)
    			for(int k=0;k<m;++k)
    				(c[i][j]+=a[i][k]*b[k][j])%=djq;
    	memcpy(a,c,sizeof(c));
    }
    
    int main()
    {
    	scanf("%d%d%d %s",&n,&m,&djq,s+1);
    	for(int i=2,j=0;i<=m;++i)
    	{
    		while(j&&s[i]!=s[j+1]) j=nxt[j];
    		if(s[i]==s[j+1]) ++j;
    		nxt[i]=j;
    	}
    	for(int i=0;i<m;++i)
    		for(char j='0';j<='9';++j)
    		{
    			int k=i;
    			while(k&&s[k+1]!=j) k=nxt[k];
    			if(s[k+1]==j) ++k;
    			++g[i][k];
    		}
    	for(int i=0;i<m;++i) res[i][i]=1;
    	for(;n;n>>=1,mul(g,g))
    		if(n&1) mul(res,g);
    	f[0][0]=1; mul(f,res);
    	for(int i=0;i<m;++i) (ans+=f[0][i])%=djq;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    k8s Helm安装Prometheus Operator
    maven私有库神坑之:“Downloading: http://repo.maven.apache.org/maven2/”深坑!!!!!!坑害了一周时间
    docker java基础镜像
    helm安装EFK
    helm部署redis主从和哨兵模式
    k8s资源存储pv pvc 动态持久化存储StorageClass
    k8s service概述
    harbor镜像仓库原理和安装
    制作免费的https证书
    OpenStack点滴03-Neutron
  • 原文地址:https://www.cnblogs.com/wzzyr24/p/12748153.html
Copyright © 2011-2022 走看看