zoukankan      html  css  js  c++  java
  • BZOJ1009:[HNOI2008]GT考试——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1009

    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

    参考:http://hzwer.com/2955.html 和 http://blog.csdn.net/cjk_cjk/article/details/43038377

    有一个很显然的dp,设f[i][j]表示j长度的准考证号的[j-i+1,j]正好与不吉利串的[1,i]匹配上(同时准考证号没有出现过不吉利串)。

    我们显然要求的是f[0][n]+f[1][n]+f[2][n]……+f[m-1][n]

    显然n太大了,我们需要对此优化。

    考虑到f[i][j]=sigma(f[k][j-1])(通过枚举尾部放哪个字符来决定k进行转移)

    上式我们简化为f[i][j]=f[j-1][0]*a[0][i]+f[j-1][1]*a[1][i]+…+f[j-1][m-1]*a[m-1][i]

    显然我们能够处理出a数组(看上面括号),而且想一想就可以得到初始的f就是a*单位矩阵,那么剩下的就是矩阵乘法快速幂了。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    int n,m,k;
    char s[50];
    int nxt[50];
    void getnxt(){
        for(int i=2,j=0;i<=m;i++){
            while(j&&s[i]!=s[j+1])j=nxt[j];
            if(s[i]==s[j+1])j++;
            nxt[i]=j;
        }
        return;
    }
    struct node{
        int g[21][21];
    };
    void buildI(node &a){
        for(int i=0;i<m;i++){
            for(int j=0;j<m;j++){
                a.g[i][j]=(i==j);
            }
        }
    }
    void multi(node x,node y,node &z){
        memset(z.g,0,sizeof(z.g));
        for(int i=0;i<m;i++){
            for(int j=0;j<m;j++){
                if(x.g[i][j]){
                    for(int l=0;l<m;l++){
                        z.g[i][l]+=x.g[i][j]%k*y.g[j][l]%k;
                        z.g[i][l]%=k;
                    }
                }
            }
        }
        return;
    }
    node a,b;
    void qpow(int k){
        buildI(a);
        while(k){
            if(k&1)multi(a,b,a);
            multi(b,b,b);
            k>>=1;
        }
        return;
    }
    int solve(){
        int ans=0;
        qpow(n);
        for(int i=0;i<m;i++){
            ans+=a.g[0][i];
            ans%=k;
        }
        return ans;
    }
    int main(){
        scanf("%d%d%d%s",&n,&m,&k,s+1);
        getnxt();
        for(int i=0;i<m;i++){
            for(char j='0';j<='9';j++){
                int t=i;
                while(t&&s[t+1]!=j)t=nxt[t];
                if(s[t+1]==j)t++;
                if(t!=m){
                    b.g[i][t]++;b.g[i][t]%=k;
                }
            }
        }
        printf("%d
    ",solve());
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Python之路【第七十一篇】:django日更
    Python之路【第七十篇】:django日更
    Python之路【第六十九篇】:django日更
    选包
    Python之路【第六十八篇】:django日更
    Python之路【第六十七篇】:django日更
    Python之路【第六十六篇】:django日更
    Python之路【第六十五篇】:django日更
    Python之路【第六十四篇】:django日更
    Python之路【第六十三篇】:django日更
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8401276.html
Copyright © 2011-2022 走看看