• [HNOI2008]GT考试


    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    [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
     
    朴素的DP
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char s[21];
    int fail[21],f[21][10],dp[100001][21];
    int n,m,mod;
    void pre()
    { 
        for(int i=1;i<m;i++)
        {
            int j=fail[i];
            while(j && s[j]!=s[i]) j=fail[j];
            fail[i+1]=s[j]==s[i] ? j+1 : j;
        }
        for(int i=1;i<=m;i++)
            for(int j=0;j<=9;j++)
                {
                    int k=fail[i-1];
                    while(k && s[k]-'0'!=j) k=fail[k];
                    f[i][j]=s[k]-'0'==j ? k+1 : k;
                }    
        //f[i][j] 填了i位,最后一位是j,可以匹配的长度 
    }
    #define MOD(x) x= x>=mod ? x-=mod : x
    void dp_()
    {
        dp[1][1]=1%mod;
        dp[1][0]=9%mod;
        int t;
        for(int i=1;i<n;i++)
            for(int j=0;j<=min(m-1,i);j++)
                for(int k=0;k<=9;k++)
                    if(s[j]-'0'==k) dp[i+1][j+1]+=dp[i][j],MOD(dp[i+1][j+1]);
                    else dp[i+1][f[j+1][k]]+=dp[i][j],MOD(dp[i+1][f[j+1][k]]);
        int ans=0;
        for(int i=0;i<m;i++) ans+=dp[n][i],MOD(ans);
        printf("%d",ans);
        //dp[i][j] 填了i位,最后j位与不吉利数字前j位相同 
    }
    int main()
    {
    //    freopen("bzoj_1009.in","r",stdin);
    //    freopen("bzoj_1009.out","w",stdout);
        scanf("%d%d%d",&n,&m,&mod);
        scanf("%s",s);
        pre();
        dp_();
    }

    矩阵乘法优化

    不写了,推荐一篇很详细的博客

    http://blog.csdn.net/Jaihk662/article/details/75331761?locationNum=1&fps=1

    dp矩阵主对角线全赋值为1——单位矩阵

    任何矩阵*单位矩阵=本身

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MOD(x) x= x>=mod ? x%=mod : x
    using namespace std;
    char s[21];
    int fail[21],f[21][21],dp[21][21];
    int n,m,mod;
    int tmp[21][21];
    void pre()
    { 
        int j=0; 
        for(int i=2;i<=m;i++)
        {
            while(j && s[j+1]!=s[i]) j=fail[j];
            if(s[j+1]==s[i]) j++;
            fail[i]=j;
        }
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<=9;j++)
            {
                int t=i;
                while(t && s[t+1]-'0'!=j) t=fail[t];
                if(s[t+1]-'0'==j) t++;
                if(t!=m) f[i][t]++,MOD(f[i][t]);
            }
        }
    }
    void pow(int a[21][21],int b[21][21],int c[21][21])
    {
        memset(tmp,0,sizeof(tmp));
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                for(int k=0;k<m;k++)
                    tmp[i][j]+=a[i][k]*b[k][j],MOD(tmp[i][j]);
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                c[i][j]=tmp[i][j];
    }
    void dp_()
    {
        for(int i=0;i<m;i++) dp[i][i]=1;
        for(;n;n>>=1,pow(f,f,f))
            if(n&1) pow(dp,f,dp);
        int ans=0;
        for(int i=0;i<m;i++) ans+=dp[0][i],MOD(ans);
        printf("%d",ans);
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&mod);
        scanf("%s",s+1);
        pre();
        dp_();
    }
     
  • 相关阅读:
    Atitti. 语法树AST、后缀表达式、DAG、三地址代码
    Atitit.antlr实现词法分析
    Atitit.antlr实现词法分析
    Atitit.词法分析的理论原理 part2
    Atitit.词法分析的理论原理 part2
    atitit.词法分析原理 词法分析器 (Lexer)
    atitit.词法分析原理 词法分析器 (Lexer)
    Atitti.数据操作crud js sdk dataServiceV3设计说明
    Atitti.数据操作crud js sdk dataServiceV3设计说明
    Atitit.http代理的实现 代码java php c# python
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7468728.html
Copyright © 2020-2023  润新知