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

    题目描述

    阿申准备报名参加 GT 考试,准考证号为 N 位数X1,X2Xn(0Xi9),他不希望准考证号上出现不吉利的数字。 他的不吉利数学A1,A2Am(0Ai9) 有 M位,不出现是指 X1,X2Xn 中没有恰好一段等于 A1,A2Am,A1X1 可以为 0

    输入输出格式

    输入格式:

     

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

     

    输出格式:

     

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

    输入输出样例

    输入样例#1: 
    4 3 100
    111
    输出样例#1: 
    81

    说明

    N≤10^9,M≤20,K≤1000

    一些思路:

    一道DP&&矩阵快速幂的题

    首先,我们用DP式子表示出这道题所要求的值

    设dp[i][j]表示X串前i位后缀匹配了A串的前j位,g[i][j]表示从匹配A串前i位变到前j位的方案数,没有就是0

    易知,$dp[i][j]=sumlimits_{k=0}^{m-1} dp[i-1][k]*g[k][j]$

    答案即为$sumlimits_{i=0}^{m-1} dp[n-1][i]$

    我们会发现这是一个矩阵乘幂的式子

    然后用矩阵快速幂乱搞一通即可

    弱弱的说一句,其实我觉得这道题的预处理g[i][j]也蛮难的

    上代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dwn(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    int a[50][50],m,n,mod,k,zlk[50][50],ans[50][50],sum,haha;
    char ch[50];
    void check(int x,int y){
    	if(x+1<y || (ch[x+1]==ch[y] && y<x+1)) return;
    	rep(i,1,y-1){
    		if(ch[i]!=ch[x-y+1+i]) return;
    	}
    	rep(i,y+1,m-1) if(a[x][i] && ch[i]==ch[y]) return;
    	a[x][y]=1;
    	return;
    }
    void ksm(){
    	while(k){
    		if(k&1){
    			memset(zlk,0,sizeof(zlk));
    			rep(i,0,m-1) rep(j,0,m-1) rep(k,0,m-1) zlk[i][j]+=ans[i][k]*a[k][j],zlk[i][j]%=mod;
    			rep(i,0,m-1) rep(j,0,m-1) ans[i][j]=zlk[i][j];
    		}
    		memset(zlk,0,sizeof(zlk));
    		rep(i,0,m-1) rep(j,0,m-1) rep(k,0,m-1) zlk[i][j]+=a[i][k]*a[k][j],zlk[i][j]%=mod;
    		rep(i,0,m-1) rep(j,0,m-1) a[i][j]=zlk[i][j];
    		k>>=1; 
    	}
    }
    bool wk(int x,int y){
    	rep(i,1,x+1){
    		bool c=0;
    		rep(j,1,i-1) if(ch[j]!=ch[x-i+j+1]){c=1; break;}
    		if(!c && y+'0'==ch[i]) return 0;
    	}
    	return 1;
    }
    int main(){
        scanf("%d%d%d",&k,&m,&mod);
        cin>>ch+1;
        rep(i,1,m-2) dwn(j,m-1,1)  check(i,j);
        dwn(j,m-1,1){
    	    check(m-1,j);
    	    if(a[m-1][j] && ch[j]==ch[m]) a[m-1][j]=0;
        }
        dwn(i,m-1,0) rep(j,0,9)	if(wk(i,j)) a[i][0]++;
        a[0][1]=1;
        rep(i,0,m-1) ans[i][i]=1;
        ksm();
        rep(i,0,m-1) sum+=ans[0][i],sum%=mod;
        printf("%d",sum);
    	return 0;
    }
    

      

  • 相关阅读:
    emWin 界面切换注意事项
    emWin 工程之汉字显示
    emWin 使用 GUIBuilder 放置标题 TEXT 注意
    【转】系统调用和驱动程序中相应函数的参数对应关系
    主机 & 虚拟机 & 开发板 相互通信
    电脑通过网口连接开发板
    【转】ARM交叉编译工具链
    【转】vi 写完文件保存时才发现是 readonly
    【转】ubuntu 12.04下如何开启 NFS 服务 & 设置
    安装完打开 eclipse 提示 JVM 版本较低
  • 原文地址:https://www.cnblogs.com/handsome-zlk/p/10532872.html
Copyright © 2011-2022 走看看