[HNOI2008]GT考试
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位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
Sample Output
81
HINT
Solution:
利用动态规划计数。我们设计状态为f[i][j],表示目前位于准考证号的第i位,匹配到不吉利数字的第j位,这样转移方程显然,我们只需要利用kmp即可。
显然f[i][] -> f[i+1][]的转移对于任意一个i都是一样的,这就启发我们利用矩阵乘法加速。
Code :
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
using namespace std;
const int inf=~0U>>1,maxm=20;
int n,m,mod,A[maxm],next[maxm+1];
struct Mat
{
int M[maxm][maxm];
Mat(){memset(M,0,sizeof(M));}
void operator=(const Mat&o)
{memcpy(M,o.M,sizeof(M));}
int& operator()(int i,int j){return M[i][j];}
Mat operator*(Mat&o)
{
Mat T;
rep(i,m)rep(j,m)rep(k,m)T(i,j)+=M[i][k]*o(k,j),T(i,j)%=mod;
return T;
}
}orig;
Mat Power(int n)
{
if(n==1) return orig;
Mat tmp=Power(n/2);
tmp=tmp*tmp;
if(n&1) tmp=tmp*orig;
return tmp;
}
int main()
{
cin>>n>>m>>mod;char x;
rep(i,m) cin>>x,A[i+1]=x-'0';
next[1]=0;int t=0;
for(int i=2;i<=m;i++)
{
while(t>0&&A[t+1]!=A[i]) t=next[t];
if(A[t+1]==A[i])++t;
next[i]=t;
}
for(int i=0;i<m;++i)
{
rep(j,10)
{
int t=i;
while(t>0&&A[t+1]!=j)t=next[t];
if(A[t+1]==j)++t;
orig(t,i)++;
}
}
Mat ans=Power(n);int Ans=0;
rep(i,m) Ans+=ans(i,0),Ans%=mod;
cout<<Ans<<endl;
}