BZOJ 1009: [HNOI2008]GT考试
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3434 Solved: 2109
[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位的数。 N<=10^9,M<=20,K<=1000
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
111
Sample Output
81
HINT
Source
分析:
我们可以想到这题可以用$DP$来完成,$f[i][j]$代表构造方案的第$i$个字符匹配上了不吉利数字的第$j$个字符的合法方案数,然后我们枚举下一位填哪个数字转移到哪里,如果我们枚举的数字$k$恰好匹配上了第$j+1$个不吉利数字,那么就可以转移到$f[i+1][j+1]$,否则我们就通过$kmp$来找到转移的状态...
发现不吉利数字的长度很小,方案数字的长度很大,所以可以用矩阵快速幂来优化转移...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=20+5; int n,m,mod,nxt[maxn]; char s[maxn]; struct Matrix{ int a[maxn][maxn]; inline void clear(void){ memset(a,0,sizeof(a)); } friend Matrix operator * (Matrix x,Matrix y){ Matrix ans;ans.clear(); for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) (ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod)%=mod; return ans; } inline Matrix power(Matrix M,int x){ Matrix ans;ans.clear(); for(int i=0;i<n;i++) ans.a[i][i]=1; while(x){ if(x&1) ans=ans*M; M=M*M,x>>=1; } return ans; } }G; inline void getnxt(void){ nxt[0]=nxt[1]=0;int k; for(int i=1;i<n;i++){ k=nxt[i]; while(k&&s[i+1]!=s[k+1]) k=nxt[k]; if(s[i+1]==s[k+1]) nxt[i+1]=k+1; else nxt[i+1]=0; } } inline void getmatrix(void){ for(int i=0;i<n;i++) for(int j=0,k;j<=9;j++){ k=i; while(k&&(int)(s[k+1]-'0')!=j) k=nxt[k]; if((int)(s[k+1]-'0')==j) k++; else k=0; G.a[i][k]++; } } inline int solve(void){ G=G.power(G,m); int ans=0; for(int i=0;i<=n;i++) (ans+=G.a[0][i])%=mod; return ans; } signed main(void){ scanf("%d%d%d%s",&m,&n,&mod,s+1);G.clear(); getnxt();getmatrix();printf("%d\n",solve()); return 0; }
By NeighThorn