【BZOJ】【1009】 【HNOI2008】GT考试

DP/KMP/矩阵乘法


  好神的题啊……跪了跪了

  $n\leq 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。

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

  很明显这个范围O(n)是不可能的了= =必须要加速!那么我们来研究一下这个转移:我们可以把$f_i$看作一个向量:$$\begin{bmatrix} f_0 f_1 \cdots f_{m-1} \end{bmatrix}(即0\leq j\leq m-1) $$ 从$f_i$转移到$f_{i+1}$,其实是可以用一个矩阵来表示的: $$ \begin{bmatrix} f_0& f_1 &\cdots &f_{m-1} \end{bmatrix}_{i} * \begin{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} = \begin{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\n",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]
posted @ 2015-04-09 21:22  Tunix  阅读(1180)  评论(0编辑  收藏  举报