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

    BZOJ 1009: [HNOI2008]GT考试

    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

    Solution

    这一题显然是数位dp的老套路了,之前做过一个ac自动机多串的dp。
    这只有一个串显然是用kmp了。但是n<=10^9需要考虑优化。
    观察dp方程:

    (f[i][j]=sum_{k=0}^{m-1}f[i-1][k]*a[k][j])

    f[i][j]表示放到第i个后缀ji为匹配串的前缀1j。a[k][j]为加一个字母由k转移到j的放置方案数。
    f显然是线性转移,可以使用矩阵快速幂优化,完美的过了本题。

    Code

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #define fo(i,a,b) for(int i=a;i<=b;i++)
    #define fd(i,a,b) for(int i=a;i>=b;i--)
    #define rep(i,x) for(int i=head[x];i;i=e[i].next)
    #define mem(a,x) memset(a,x,sizeof(a))
    typedef long long LL;
    typedef double DB;
    using namespace std;
    inline int read() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
    }
    const int SZ=1000010,INF=0x3f3f3f3f;
    int n,m,mod,next[233];
    char s[233];
    void get_next() {
    	int l=strlen(s);
    	next[0]=next[1]=0;
    	fo(i,1,l-1) {
    		int j;
    		for(j=next[i];j&&s[i]!=s[j];j=next[j]);
    		next[i+1]=(s[i]==s[j])?j+1:0;
    	}
    }
    struct matrix {
    	int n,m,num[30][30];
    	matrix(int a,int b):n(a),m(b) {memset(num,0,sizeof(num));}
    };
    matrix operator *(const matrix &a,const matrix &b) {
    	matrix ans(a.n,b.m);
    	fo(i,0,ans.n-1) fo(j,0,ans.m-1) fo(k,0,a.m-1)
    		ans.num[i][j]=(ans.num[i][j]+(LL)a.num[i][k]*b.num[k][j]%mod)%mod;
    	return ans;
    }
    matrix ksm(matrix a,int b) {
    	matrix ans(a.n,a.m);
    	fo(i,0,ans.n-1) ans.num[i][i]=1;
    	for(;b;a=a*a,b>>=1) if(b&1) ans=ans*a;
    	return ans;
    }
    int main() {
    	freopen("1009.in","r",stdin);
    	n=read(),m=read(),mod=read(),scanf("%s",s),get_next();
    	matrix f(m,m);
    	fo(i,0,m-1) fo(j,0,9) {
    		int k;
    		for(k=i;k&&s[k]!='0'+j;k=next[k]);
    		if(s[k]=='0'+j) k++;
    		if(k!=m) f.num[i][k]++;
    	}
    	matrix fn=ksm(f,n),a(1,m);
    	a.num[0][0]=1;
    	a=a*fn;
    	int ans=0;
    	fo(i,0,m-1) ans=(ans+a.num[0][i])%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Windows10关机问题----只有“睡眠”、“更新并重启”、“更新并关机”,但是又不想更新,解决办法
    3ds max学习笔记(九)-- 实例操作(路径阵列)
    3ds max学习笔记(八)-- 实例操作(直行楼梯)
    3ds max学习笔记(七)-- 实例操作(桌子)
    3ds max学习笔记(六)-- 基本操作(建模前奏)
    UE4入门(二)建立和打开项目
    3ds max学习笔记(五)--操作工具
    3ds max 学习笔记(四)--创建物体
    3ds max学习笔记(一)--选择物体
    欧拉回路输出(DFS,不用回溯!)Watchcow POJ 2230
  • 原文地址:https://www.cnblogs.com/patricksu/p/8016515.html
Copyright © 2011-2022 走看看