题目
做法
朴素做法:
设数组(dp[i][j])为前(i)位后缀(j)位恰好(避免特判)对应禁止字符前缀(j)位
(dp[i][j]=sumlimits_{c=0}^m k[c] dp[i-1][c]),由于是恰好对应,系数(k)靠(KMP)随便搞搞就出来了
和数位dp差不多
丢到矩阵里快速幂
My complete code
#include<bits/stdc++.h>
using namespace std;
typedef int LL;
const LL maxn=31;
LL n,m,p,ans;
LL nxt[maxn],a[maxn][maxn];
char s[maxn];
struct Mat{
LL v[maxn][maxn];
inline void Init(LL x=0){
memset(v,0,sizeof(v));
for(LL i=0;i<m;++i) v[i][i]=x;
}
}M;
inline Mat Mul(const Mat &a,const Mat &b){
Mat c; c.Init();
for(LL i=0;i<m;++i)
for(LL j=0;j<m;++j)
for(LL k=0;k<m;++k)
c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%p;
return c;
}
inline Mat Fpow(Mat base,LL b){
Mat ret; ret.Init(1);
while(b){
if(b&1) ret=Mul(ret,base);
base=Mul(base,base),b>>=1;
}return ret;
}
int main(){
scanf("%d%d%d %s",&n,&m,&p,s);
LL len(strlen(s)),k(0);
for(LL i=1;i<m;++i){
while(k && s[k]!=s[i])
k=nxt[k-1];
if(s[k]==s[i]) ++k;
nxt[i]=k;
}
a[0][s[0]-'0']=1;
for(LL i=1;i<m;++i)
for(LL ch=0;ch<=9;++ch){
LL k(i);
char c(ch+'0');
while(k && s[k]!=c)
k=nxt[k-1];
if(s[k]==c) ++k;
a[i][ch]=k;
}
M.Init();
for(LL i=0;i<m;++i)
for(LL ch=0;ch<=9;++ch)
++M.v[i][a[i][ch]];
M=Fpow(M,n);
for(LL i=0;i<m;++i)
ans=(ans+M.v[0][i])%p;
printf("%d",ans);
return 0;
}