zoukankan      html  css  js  c++  java
  • 【转载】BZOJ 1009 【HNOI2008】 GT考试

    /*这道题因为有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取余的结果.

     
      这道题一眼看去像是一道容斥dp,仔细思考后发现其实普通的dp就可以做了。
      我们令fi,jfi,j表示准考证号确定了前i位,其中最后一段已经和不吉利串匹配了jj位的方案数。那么,显然我们只需要枚举每一位选什么数字即可。至于加了一位数字之后最后一段匹配了多少位,完全可以用kmpkmp来解决。因为kmpkmp算法中nextnext数组的含义就是不为整个串的前缀与后缀相等的最大长度。
      但是,这样的复杂度是O(NM2)O(NM2)的。观察发现,MM特别小,于是可以把转移矩阵预处理出来,使用矩阵快速幂优化即可。
      下面贴代码:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
     
    using namespace std;
    typedef long long llg;
     
    int n,m,k,nt[22],ans;
    char s[22];
    void gi(int &x){if(x>=k) x%=k;}
    struct matrix{
        int w[23][23];
        matrix(){memset(w,0,sizeof(w));}
        void fu(){for(int i=0;i<m;i++) w[i][i]=1;}
        matrix operator * (const matrix &h)const{
            matrix a;
            for(int i=0;i<m;i++)
                for(int j=0;j<m;j++)
                    for(int k=0;k<m;k++)
                        a.w[i][j]+=w[i][k]*h.w[k][j],gi(a.w[i][j]);
            return a;
        }
    }A,Aa;
     
    int getint(){
        int w=0;bool q=0;
        char c=getchar();
        while((c>'9'||c<'0')&&c!='-') c=getchar();
        if(c=='-') c=getchar(),q=1;
        while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
        return q?-w:w;
    }
     
    matrix mi(matrix a,int b){
        matrix s; s.fu();
        while(b){
            if(b&1) s=s*a;
            a=a*a; b>>=1;
        }
        return s;
    }
     
    int main(){
        File("a");
        n=getint(); m=getint(); k=getint();
        scanf("%s",s+1);
        for(int i=2,j=0;i<=m;i++){
            while(j && s[j+1]!=s[i]) j=nt[j];
            if(s[j+1]==s[i]) j++;
            nt[i]=j;
        }
        for(int i=0,x;i<m;i++)
            for(int j=0;j<=9;j++){
                x=i;
                while(x && s[x+1]-'0'!=j) x=nt[x];
                if(s[x+1]-'0'==j) x++;
                if(x<m) A.w[i][x]++;
            }
        Aa=mi(A,n);
        for(int i=0;i<m;i++) ans+=Aa.w[0][i],gi(ans);
        printf("%d",ans);
    }
    

      

  • 相关阅读:
    网页加速的14条优化法则 网站开发与优化
    .NET在后置代码中输入JS提示语句(背景不会变白)
    C语言变量声明内存分配
    SQL Server Hosting Toolkit
    An established connection was aborted by the software in your host machine
    C语言程序设计 2009春季考试时间和地点
    C语言程序设计 函数递归调用示例
    让.Net 程序脱离.net framework框架运行
    C语言程序设计 答疑安排(2009春季 110周) 有变动
    软件测试技术,软件项目管理 实验时间安排 2009春季
  • 原文地址:https://www.cnblogs.com/YMY666/p/8544919.html
Copyright © 2011-2022 走看看