• BZOJ 1009: [HNOI2008]GT考试


    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3434  Solved: 2109
    [Submit][Status][Discuss]

    Description

      阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
    他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为
    0

    Input

      第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

    Output

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

    Sample Input

    4 3 100
    111

    Sample Output

    81

    HINT

     

    Source

    分析:

     我们可以想到这题可以用$DP$来完成,$f[i][j]$代表构造方案的第$i$个字符匹配上了不吉利数字的第$j$个字符的合法方案数,然后我们枚举下一位填哪个数字转移到哪里,如果我们枚举的数字$k$恰好匹配上了第$j+1$个不吉利数字,那么就可以转移到$f[i+1][j+1]$,否则我们就通过$kmp$来找到转移的状态...

    发现不吉利数字的长度很小,方案数字的长度很大,所以可以用矩阵快速幂来优化转移...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=20+5;
    
    int n,m,mod,nxt[maxn];
    
    char s[maxn];
    
    struct Matrix{
    	
    	int a[maxn][maxn];
    	
    	inline void clear(void){
    		memset(a,0,sizeof(a));
    	}
    	
    	friend Matrix operator * (Matrix x,Matrix y){
    		Matrix ans;ans.clear();
    		for(int i=0;i<n;i++)
    			for(int j=0;j<n;j++)
    				for(int k=0;k<n;k++)
    					(ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod)%=mod;
    		return ans;
    	}
    	
    	inline Matrix power(Matrix M,int x){
    		Matrix ans;ans.clear();
    		for(int i=0;i<n;i++)
    			ans.a[i][i]=1;
    		while(x){
    			if(x&1)
    				ans=ans*M;
    			M=M*M,x>>=1;
    		}
    		return ans;
    	}
    	
    }G;
    
    inline void getnxt(void){
    	nxt[0]=nxt[1]=0;int k;
    	for(int i=1;i<n;i++){
    		k=nxt[i];
    		while(k&&s[i+1]!=s[k+1])
    			k=nxt[k];
    		if(s[i+1]==s[k+1])
    			nxt[i+1]=k+1;
    		else
    			nxt[i+1]=0;
    	}
    }
    
    inline void getmatrix(void){
    	for(int i=0;i<n;i++)
    		for(int j=0,k;j<=9;j++){
    			k=i;
    			while(k&&(int)(s[k+1]-'0')!=j)
    				k=nxt[k];
    			if((int)(s[k+1]-'0')==j)
    				k++;
    			else
    				k=0;
    			G.a[i][k]++;
    		}
    }
    
    inline int solve(void){
    	G=G.power(G,m);
    	int ans=0;
    	for(int i=0;i<=n;i++)
    		(ans+=G.a[0][i])%=mod;
    	return ans;
    }
    
    signed main(void){
    	scanf("%d%d%d%s",&m,&n,&mod,s+1);G.clear();
    	getnxt();getmatrix();printf("%d
    ",solve());
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    Java多态性理解
    多态详解
    public static void main(String[] args){}函数诠释
    继承、封装
    面向对象的理解
    重载与构造函数的解析
    冒泡排序及二分查找
    数组总结之补充
    计算机中如何表示数字-07IEEE754浮点数标准
    synchronized 和ReentrantLock
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6409792.html
Copyright © 2020-2023  润新知