求方案数,显然这个题得动态规划。。。
设$f(i,j)$为母串长为$i$位,子串当前匹配到了第$j$位的方案数。考虑$f(i,j)$向$i+1$转移:
枚举$i+1$的数字,然后就会发现这玩意可以用$kmp$转移。预处理出$next$数组后,转移时和普通的$kmp$匹配一样跳$next$数组,直到匹配到最长前缀转移过去。
初值$f(0,0)=1$,答案$ans=\sum\limits_{i=0}^{i<m}f(n,i)$
伪代码:
f[0][0]=1;
for(int i=0;i<n;++i)
for(int j=0;j<m;++j)
for(int k='0';k<='9';++k){//枚举下一位
int l=j;
while(l&&a[l+1]!=k)l=next[l];
if(a[l+1]==k)++l;
//和kmp一样以k为i+1位的数字匹配
(f[i+1][l]+=f[i][j])%=mod;
}
int ans=0;
for(int i=0;i<m;++i)
(ans+=f[n][i])%=mod;
复杂度不会证,反正不低于$O(10nm)$。这个式子可以用矩阵快速幂优化。把$f(i-1,0$ ~ $m-1)$和$f(i,0$ ~ $m-1)$扔进去,枚举每一个$j$和第$i+1$位的数字,在矩阵上对应的位置$+1$。
显然$f(1,0)=9,f(1,1)=1$,然后直接矩乘就好了。
矩阵大小:$(2m)*(2m)$,复杂度$O(40^3\log n)$
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
template<typename T>
inline T read(){
T x=0;
int y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int n,m,mod;
int next[50];
char a[22];
struct Matrix{
int a[50][50],l,c;
Matrix operator * (const Matrix x){
Matrix ans;
ans.l=l,ans.c=x.c;
for(register int k=0;k<c;++k)
for(register int i=0;i<l;++i)
for(register int j=0;j<x.c;++j)
(ans.a[i][j]+=a[i][k]*x.a[k][j])%=mod;
return ans;
}
Matrix(){
memset(a,0,sizeof a);
}
}start,origin;
//start为初始矩阵,origin为转移矩阵
Matrix quickpow(Matrix x,int y){
Matrix ans;
ans.l=ans.c=x.l;
for(register int i=0;i<ans.l;++i)
ans.a[i][i]=1;
while(y){
if(y&1)ans=ans*x;
x=x*x;
y>>=1;
}
return ans;
}
void kmp(){
int j=0;
for(register int i=2;i<=m;++i){
while(j&&a[j+1]!=a[i])j=next[j];
if(a[j+1]==a[i])++j;
next[i]=j;
}
}
void build(){
for(register int i=m,j=0;i<(m<<1);++i,++j)
origin.a[i][j]=1;
for(register int i=0;i<m;++i){
for(register int j='0';j<='9';++j){
int k=i;
while(k&&a[k+1]!=j)k=next[k];
if(a[k+1]==j)++k;
if(k<m)++origin.a[i+m][k+m];
//m=i、下一位为j时会对第k位产生影响
}
}
origin.l=origin.c=m<<1;
start.l=1,start.c=m<<1;
start.a[0][0]=start.a[0][m+1]=1,start.a[0][m]=9;
}
int main(){
n=read(),m=read(),mod=read();
scanf("%s",a+1);
kmp();
build();
start=start*quickpow(origin,n);
int ans=0;
for(register int i=0;i<m;++i)
(ans+=start.a[0][i])%=mod;
printf("%d\n",ans);
}