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

    [HNOI2008]GT考试

    题目描述

    阿申准备报名参加 GT 考试,准考证号为 (N) 位数(X_{1},X_{2}…X_{n}(0≤X_{i}≤9)),他不希望准考证号上出现不吉利的数字。 他的不吉利数学(A_{1},A_{2}…A_{m}(0≤A_{i}≤9))(M) 位,不出现是指 (X_{1},X_{2}…X_{n})​ 中没有恰好一段等于 (A_{1},A_{2}…A_{m}​)(A_{1})(X_{1}​) 可以为 (0)

    输入格式

    第一行输入(N),(M),(K).接下来一行输入M位的数。

    输出格式

    阿申想知道不出现不吉利数字的号码有多少种,输出模 (K) 取余的结果。

    输入输出样例

    输入 #1

    4 3 100
    111
    

    输出 #1

    81
    

    说明/提示

    (N≤10^{9},M≤20,K≤1000)

    思路分析

    本来就是想好好想练一下(KMP),根据某谷标签找到了这道题,看题面那么简短,以为并不是很难(虽然是紫的),结果做着做着就傻了
    这题很综合,(DP)+矩阵快速幂+(KMP),我原地螺旋升天sto orz

    状态转移:

    • (dp[i][j])表示长度为(i)的字符串,最后(j)个可以匹配模式串前(j)位的情况数,答案就是(sum_{i=0}^{m-1}dp[n][i])
    • However,理论是有了,如何实现?
    • 关键在于对模式串的不同匹配情况,用一个(g[k][j])对于一个匹配到长度为 (j)的串,转移到 (k) 的串的方案
    • 此时转移方程(dp[i][j] = sum_{k=0}^{m-1}dp[i-1][k]*g[k][j]),你看,你看,你仔细看,这个式子像什么?矩阵乘啊!(本蒟蒻永远推不出来系列)
    • 因为我们最后只需要(n)这一行矩阵,所以我们把每一行(dp[i][j])抽象成只有一行列数为(m-1)(F[i]),最后就变成了(F[i] = F[i-1]*G),推出(F[n] = F[0]*G^{n}),这时候就可以跑矩阵快速幂了

    等会儿,我不是来练(KMP)的吗???

    Code

    #include<bits/stdc++.h>
    #define N 25
    using namespace std;
    inline int read(){
    	int x = 0,f =  1;
    	char ch = getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,mod,kmp[N];
    char s[N];
    struct xzy{//定义矩阵
    	int a[N][N];
    	xzy(){memset(a,0,sizeof(a));}
    }G,F;
    xzy operator *(xzy a,xzy b){//矩阵乘法
    	xzy ans;
    	for(int i = 0;i < m;i++){
    		for(int j = 0;j < m;j++){
    			for(int k = 0;k < m;k++){
    				ans.a[i][j] = (ans.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
    			}
    		}
    	}
    	return ans;
    }
    xzy quickpow(xzy g,int t){//矩阵快速幂
    	xzy ans;
    	for(int i = 0;i < m;i++)ans.a[i][i] = 1;
    	while(t){
    		if(t&1)ans = ans*g;
    		g = g*g;
    		t >>= 1;
    	}
    	return ans;
    }
    int main(){
    	n=read();m=read();mod=read();
    	scanf("%s",s+1);
    	int j=0;
    	for(int i=2;i<=m;++i) {//kmp求匹配情况
    		while(j && s[j+1]!=s[i]) j=kmp[j];
    		if(s[j+1]==s[i]) j++;
    		kmp[i]=j;
    	}
    	
    	for(int i=0;i<m;++i) {//算出所有未完全匹配的个数(这好像才是我的本意……)
    		for(char ch='0';ch<='9';++ch) {//枚举所有位数
    			int j=i;
    			while(j && s[j+1]!=ch) j=kmp[j];//失配回跳
    			if(s[j+1]==ch) j++;//该情况成立
    			G.a[i][j]=(G.a[i][j]+1)%mod;//加上一种情况
    		}
    	}
    	F.a[0][0]=1;//F是一行m列的
    	G=quickpow(G,n);
    	F=F*G;
    	int ans=0;
    	for(int i=0;i<m;++i) {
    		ans=(ans+F.a[0][i])%mod;
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    request Dispatch
    xmlHTTPRequest
    java 文件上传
    文件上传(2)
    文件上传
    Tomcat 加入windows 服务自启动设置
    windows下配置两个或多个Tomcat启动的方法
    HibernateProxy异常处理 java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
    checkbox遍历操作, 提交所有选中项的值
    tomcat结合nginx使用 基础教程
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13363151.html
Copyright © 2011-2022 走看看