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

    DP/KMP/矩阵乘法


      好神的题啊……跪了跪了

      $nleq 10^9$是什么鬼……我们还是先不要考虑这个鬼畜的玩意了>_>

      用类似数位DP的思路,我们可以想到一个DP方程:$f[i][j]$表示前 i 位数字,它的最后 j 位与不吉利串匹配的方案数,显然有$ans=sum_{i=0}^x f[n][i]$

      然后就是转移的问题了= =那么依旧按照数位DP的想法(其实是硬扯到那的吧……怎么理解都可以,重点是明白转移方程)可以想到:从 i 转移到 i+1,有10种方案,其中一种会使得匹配长度+1,即$f[i+1][j+1]+=f[i][j]$那么其他的方案呢?并不都会使得匹配长度归0,想到这你大概已经想到了,对!就是KMP!字符串匹配时的fail指针!那么转移的方式就是这三种了= =:1.匹配长度归0;2.匹配长度+1;3.匹配长度变为fail[j]+1。

      那么转移方式已经确定啦~接下来就该考虑一下$nleq 10^9$这个蛋疼的范围了……

      很明显这个范围O(n)是不可能的了= =必须要加速!那么我们来研究一下这个转移:我们可以把$f_i$看作一个向量:$$egin{bmatrix} f_0 f_1 cdots f_{m-1} end{bmatrix}(即0leq jleq m-1) $$ 从$f_i$转移到$f_{i+1}$,其实是可以用一个矩阵来表示的: $$ egin{bmatrix} f_0& f_1 &cdots &f_{m-1} end{bmatrix}_{i} * egin{bmatrix} a_{0,0}& a_{0,1}& cdots &a_{0,m-1} \ a_{1,0}& a_{1,1}& cdots &a_{1,m-1} \  ddots& ddots& vdots &ddots \ a_{m-1,0}& a_{m-1,1}& cdots &a_{m-1,m-1} end{bmatrix} = egin{bmatrix} f_0 &f_1 &cdots &f_{m-1} end{bmatrix}_{i+1} $$

      嗯左边的表示$f[i][j]$,右边就是$f[i+1][j]$了;那么a矩阵是什么玩意呢?这是一个转移矩阵:$a[i][j]$表示从匹配了 i 个字符转移到匹配了 j 个字符有多少种方案!很明显当$j>0$的时候f[i][j]只可能是0或1,这里可能需要仔细理解一下,反正$f[i+1]$跟$f[i]$是线性相关的!所以我们可以直接利用矩阵乘法加速!

      嗯这道题我写的时候由于本题有【匹配长度为0】这个状态……然后KMP很久没写过了……果断跪啊,这题貌似是需要在原来的KMP上稍微改动一下,由于我KMP理解的不是很好所以蛋疼了很久……最后是看了Hzwer的写法才过的

     1 /**************************************************************
     2     Problem: 1009
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:56 ms
     7     Memory:812 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1009
    11 #include<cstdio>
    12 #define rep(i,n) for(int i=0;i<n;++i)
    13 #define F(i,j,n) for(int i=j;i<=n;++i)
    14 const int N=25,INF=~0u>>2;
    15 /******************tamplate*********************/
    16 int n,m,P;
    17 struct Matrix{
    18     int x[N][N];
    19     int* operator [] (int a) {return x[a];}
    20     Matrix(int a=0){
    21         rep(i,N) rep(j,N)
    22             if (i==j) x[i][j]=a;
    23             else x[i][j]=0;
    24     }
    25 };
    26 Matrix operator*(Matrix a,Matrix b){
    27     Matrix c;
    28     rep(i,m) rep(j,m) rep(k,m)
    29         c[i][j]=(c[i][j]+a[i][k]*b[k][j])%P;
    30     return c;
    31 }
    32 Matrix Pow(Matrix a,int b){
    33     Matrix r(1);
    34     for(;b;b>>=1,a=a*a)   if(b&1) r=r*a;
    35     return r;
    36 }
    37 /*******************Matrix**********************/
    38 char s[100];
    39 Matrix f,a;
    40 int next[100];
    41 void KMP(){
    42     int j=0;
    43     F(i,2,m){
    44         while (j && s[i]!=s[j+1]) j=next[j];
    45         if (s[j+1]==s[i]) j++;
    46         next[i]=j;
    47     }
    48     rep(i,m)
    49         rep(j,10){
    50             int x=i;
    51             while(x && s[x+1]-'0'!=j) x=next[x];
    52             if (j==s[x+1]-'0') a[i][x+1]++;
    53             else a[i][0]++;
    54         }
    55 }
    56 int main(){
    57     scanf("%d%d%d",&n,&m,&P);
    58     scanf("%s",s+1);
    59     KMP();
    60     f=Pow(a,n);
    61     int ans=0;
    62     rep(i,m) ans+=f[0][i],ans%=P;
    63     printf("%d
    ",ans);
    64     return 0;
    65 }
    View Code

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2015  Solved: 1233
    [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位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6

    Output

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

    Sample Input

    4 3 100
    111

    Sample Output

    81

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    个人记录--当前年月,求当月天数和上月
    java修改图片大小
    多层iframe的页面取子标签
    oracle的游标
    json中获取key值
    iOS开发常用代码块(2)
    大话数据结构(六)——链式存储
    项目中比较有用得到js经验
    微信公众号开发——php sdk php中curl用法
    微信页面设计weui源代码(4)——Pciker微信页面中实现下拉菜单
  • 原文地址:https://www.cnblogs.com/Tunix/p/4412201.html
Copyright © 2011-2022 走看看