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 }