GT考试
f[i][j]表示准考证号前i位的后j位与不吉利串的前j位相等
那么答案就是
转移方程:
a[i][j]表示不吉利串的第i位后加 从0~9之间的数之后变为不吉利串第j位的方案数
求a[i][j] 用kmp
大概意思就是:
(1):先跑一遍kmp 把不吉利串的fail 都先求出来
(2):for(i 0→m-1)
for(p 0→9)
求不吉利串前i位+p 的fail值
其fail值即是第i位后加上p可以转移到的位数
a[i][j] 是一个矩阵,f[i][j]也是一个矩阵(只取其中的lenm 段,相当于使其滚动起来)
↓
然后用矩阵快速幂
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 using namespace std; 6 7 int n,lenw,kk; 8 char w[31]; 9 ll a[31][31]; 10 int fail[31]; 11 ll f[31][31]; 12 13 void kmp() 14 { 15 for(int i=2,j=0;i<=lenw;++i) 16 { 17 while(j&&w[i-1]!=w[j]) 18 j=fail[j]; 19 if(w[i-1]==w[j]) 20 fail[i]=++j; 21 } 22 for(int i=0;i<lenw;++i) 23 for(int p=0;p<=9;++p) 24 { 25 int k=i; 26 while(k&&w[k]!=p+'0') 27 k=fail[k]; 28 if(w[k]==p+'0') 29 ++k; 30 ++a[i][k]; 31 } 32 33 /*for(int i=0;i<=lenw;i++) 34 { 35 //printf("\n"); 36 for(int j=0;j<=lenw;j++) 37 printf("%d ",a[i][j]); 38 printf("\n"); 39 }*/ 40 } 41 42 int temp[31][31]; 43 44 void out11() 45 { 46 printf("\n"); 47 for(int i=0;i<=lenw;i++) 48 { 49 //printf("\n"); 50 for(int j=0;j<=lenw;j++) 51 printf("%d ",f[i][j]); 52 printf("\n"); 53 } 54 printf("\n"); 55 //printf("%d",ans); 56 } 57 58 int main(){ 59 //freopen("bzoj_1009.in","r",stdin); 60 //freopen("bzoj_1009.out","w",stdout); 61 scanf("%d%d%d%s",&n,&lenw,&kk,w); 62 kmp(); 63 for(int i=0;i<=lenw;i++) 64 f[i][i]=1; 65 66 while(n) 67 { 68 if(n&1) 69 { 70 for(int i=0;i<=lenw;i++) 71 for(int j=0;j<=lenw;j++) 72 { 73 temp[i][j]=0; 74 for(int k=0;k<=lenw;k++) 75 temp[i][j]+=(f[i][k]*a[k][j])%kk; 76 } 77 for(int i=0;i<=lenw;i++) 78 for(int j=0;j<=lenw;j++) 79 f[i][j]=temp[i][j]; 80 } 81 for(int i=0;i<=lenw;i++) 82 for(int j=0;j<=lenw;j++) 83 { 84 temp[i][j]=0; 85 for(int k=0;k<=lenw;k++) 86 temp[i][j]+=(a[i][k]*a[k][j])%kk; 87 } 88 for(int i=0;i<=lenw;i++) 89 for(int j=0;j<=lenw;j++) 90 a[i][j]=temp[i][j]; 91 n>>=1; 92 //out11(); 93 } 94 ll ans=0;//cout<<0; 95 for(int i=0;i<lenw;i++) 96 { 97 ans+=f[0][i]; 98 ans%=kk; 99 } 100 printf("%lld",ans); 101 //while(1); 102 return 0; 103 }