分析
设
f[i][j]
表示前
i
位,匹配了不吉利数字的
边界:
f[0][0]=1,f[0][i]=0
。
转移:
f[i][j]=∑f[i−1][k]∗go[k][j]
,
go[k][j]
表示是否有从不吉利数字的第
k
位转移到第
答案:
res=∑f[n][i],0≤i<m
。
求 go[k][j] 用kmp,很难讲清,所以就不讲了…
动规不能直接求,不然
O(N2)
会TLE。
用矩阵快速幂。
代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
const int L=25;
struct Matrix
{
int w,h;
int p[L][L];
}f,v,r;
int n,m,k,res;
char s[L]; int pre[L];
Matrix mutiply(Matrix ma,Matrix mb)
{
Matrix rr;
memset(rr.p,0,sizeof rr.p);
rr.h=ma.h,rr.w=mb.w;
for (int i=0;i<rr.h;i++)
for (int j=0;j<rr.w;j++)
for (int d=0;d<ma.w;d++)
(rr.p[i][j]+=ma.p[i][d]*mb.p[d][j])%=k;
return rr;
}
Matrix mi(Matrix b,int i)
{
if (i==1) return b;
Matrix sum=mi(b,i>>1);
sum=mutiply(sum,sum);
if (i&1) sum=mutiply(sum,b);
return sum;
}
int main(void)
{
scanf("%d%d%d%s",&n,&m,&k,&s[1]);
int j=0;
for (int i=2;i<=m;i++)
{
for (;j&&s[i]^s[j+1];j=pre[j]);
pre[i]=j+=s[i]==s[j+1];
}
int sum;
for (int i=0;i<m;i++)
for (char c='0';c<='9';c++)
{
for (j=i;j&&s[j+1]^c;j=pre[j]);
j+=s[j+1]==c;
if (j^m) v.p[i][j]++;
}
v.w=v.h=m;
f.p[0][0]=1,f.h=1,f.w=m;
r=mutiply(f,mi(v,n));
for (int i=0;i<m;i++) (res+=r.p[0][i])%=k;
printf("%d\n",res);
return 0;
}