# 【BZOJ1009】[HNOI2008] GT考试（KMP+矩阵乘法）

### 代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 20
using namespace std;
int n,m,X;char s[M+5];
namespace KMP
{
int nxt[M+5];
I void GetNxt()//求出nxt数组
{
RI i,j;for(i=2,nxt[1]=j=0;i<=m;++i)
{W(j&&s[j+1]^s[i]) j=nxt[j];s[j+1]==s[i]&&++j,nxt[i]=j;}
}
}
class Mat
{
private:
int n,m,a[M+5][M+5];
public:
I Mat(CI x=0,CI y=0):n(x),m(y){memset(a,0,sizeof(a));}
I int* operator [] (CI x) {return a[x];}
I Mat operator * (Con Mat& o) Con//矩阵乘法
{
Mat t(n,o.m);int i,j,k;for(i=0;i<=t.n;++i) for(j=0;j<=t.m;++j)
for(k=0;k<=m;++k) t[i][j]=(1LL*a[i][k]*o.a[k][j]+t[i][j])%X;return t;
}
I Mat operator ^ (RI y) Con//矩阵快速幂
{
Mat x=*this,t(n,m);for(RI i=0;i<=n;++i) t[i][i]=1;
W(y) y&1&&(t=t*x,0),x=x*x,y>>=1;return t;
}
}S,U;
int main()
{
RI i,j;scanf("%d%d%d%s",&n,&m,&X,s+1),KMP::GetNxt();
RI v,p,fg;for(U=Mat(m,m),i=0;i^m;++i)//求出转移矩阵
{
p=fg=0,j=i;W(v=s[j+1]&15,!((fg>>v)&1)&&(++p,fg|=1<<v,U[i][j+1]=1),j) j=KMP::nxt[j];//不断枚举nxt，每种数字只能转移一次
U[i][0]=(10-p)%X;//求出转移到第0位的方案数
}
RI t=0;for(S=Mat(0,m),S[0][0]=1,S=S*(U^n),i=0;i^m;++i) (t+=S[0][i])>=X&&(t-=X);//矩乘之后统计答案
return printf("%d",t),0;
}

posted @ 2020-02-01 10:28  TheLostWeak  阅读(...)  评论(...编辑  收藏