BZOJ[1009] [HNOI2008]GT考试

了了已久的心结

f[i][j]表示到第i为,长度为j的后缀与不吉利数字的前缀相同,其实这个和一些期望概率的DP类似,利用a数组记录当前j在加上不同的数字之后,可以分别转移至那些状态,用KMP处理一下,然后矩阵快速幂就行了

Code

 

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 typedef long long LL;
 9 int n,m,mod;
10 char s[25];
11 int nxt[30];
12 LL a[30][30];
13 void Getnxt(){
14     nxt[0]=-1;
15     int i=0,j=-1;
16     while(i<m){
17         if(j==-1 || s[i]==s[j]){
18             i++; j++;
19             nxt[i]=j; 
20         }
21         else j=nxt[j];
22     }
23 }
24 void Geta(){
25     for(int i=0;i<m;i++){
26         for(int j=0;j<=9;j++){
27             char c='0'+j;
28             int tmp=i+1;
29             while(tmp!=-1 && s[tmp]!=c) tmp=nxt[tmp];
30             if(tmp==-1) a[i+1][0]=(a[i+1][0]+1)%mod;
31             else a[i+1][tmp+1]=(a[i+1][tmp+1]+1)%mod;
32          }
33     }
34     a[0][1]=1; a[0][0]=9;
35 }
36 LL f[30];
37 LL d[30];
38 void cheng1(){
39     memset(d,0,sizeof(d));
40     for(int i=0;i<m;i++){
41         for(int j=0;j<m;j++){
42             d[j]+=f[i]*a[i][j];
43             d[j]%=mod;
44         }
45     }
46     memcpy(f,d,sizeof(d));
47 }
48 LL e[30][30];
49 void cheng2(){
50     memset(e,0,sizeof(e));
51     for(int i=0;i<m;i++){
52         for(int j=0;j<m;j++){
53             for(int k=0;k<m;k++){
54                 e[i][j]+=a[i][k]*a[k][j];
55                 e[i][j]%=mod;
56             }
57         }
58     }
59     memcpy(a,e,sizeof(a));
60 }
61 void DP(){
62     int b=n;
63     f[1]=1; f[0]=9;
64     b--;
65     while(b){
66         if(b&1) cheng1();
67         b=b>>1; cheng2();
68     }
69     LL ans=0;
70     for(int i=0;i<m;i++){
71         ans+=f[i]; ans%=mod;
72     }
73     cout<<ans<<endl;
74 }
75 int main(){
76     scanf("%d%d%d",&n,&m,&mod);
77     scanf("%s",&s);
78     Getnxt();
79     Geta();
80     DP();
81     
82 }
View Code

 

posted @ 2017-10-16 16:51  Nawox  阅读(171)  评论(0编辑  收藏  举报