题目大意:
准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数
他的不吉利数A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am
A1和X1可以为0
思路:
dp i j 为第i个号码匹配到第j个不吉利数字的方案数
可以得到:dp[i][j]=∑dp[i−1][k]∗t[k][j](0<=k<=m−1)
其中t数组为第i位加的字符的方案数使从匹配k位到匹配j位的方案数
可以使用kmp算法来求出t数组
然后这个式子可以矩阵乘法加速
同样在图上填一填数
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<queue> 8 #include<map> 9 #include<vector> 10 #define ll long long 11 #define inf 2147483611 12 #define MAXN 1010 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,m,MOD,nxt[25]; 22 char str[25]; 23 struct mat{int num[25][25];}ans,t; 24 mat mul(mat a,mat b) 25 { 26 mat res; 27 memset(res.num,0,sizeof(res.num)); 28 for(int i=0;i<m;i++) 29 for(int j=0;j<m;j++) 30 for(int k=0;k<m;k++) 31 (res.num[i][j]+=a.num[i][k]*b.num[k][j])%=MOD; 32 return res; 33 } 34 int q_pow(int n) 35 { 36 int res=0; 37 while(n) 38 { 39 if(n&1) ans=mul(ans,t); 40 t=mul(t,t); 41 n>>=1; 42 } 43 for(int i=0;i<m;i++) (res+=ans.num[0][i])%=MOD; 44 return res; 45 } 46 int main() 47 { 48 n=read(),m=read(),MOD=read(); 49 scanf("%s",str+1);int j=0,tmp; 50 for(int i=2;i<=m;i++) 51 { 52 while(j&&str[j+1]!=str[i]) j=nxt[j]; 53 if(str[j+1]==str[i]) j++; 54 nxt[i]=j; 55 //cout<<i<<" "<<nxt[i]<<endl; 56 } 57 memset(t.num,0,sizeof(t.num)); 58 memset(ans.num,0,sizeof(ans.num)); 59 for(int i=0;i<m;i++) 60 for(int j=0;j<=9;j++) 61 { 62 tmp=i; 63 while(tmp&&str[tmp+1]!=(char)(j+'0')) tmp=nxt[tmp]; 64 if(str[tmp+1]==(char)(j+'0')) tmp++; 65 if(tmp!=m) t.num[i][tmp]++; 66 //cout<<i<<" "<<tmp<<endl; 67 } 68 for(int i=0;i<m;i++) ans.num[i][i]=1; 69 printf("%d",q_pow(n)); 70 }