妈耶之前因为不熟KMP一直觉得这题好难,现在发现当年真是naive
首先我们容易设出一个DP,(f_{i,j})表示准考证上前(i)位的长度为(j)的后缀与不吉利的数字的长度为(j)的前缀匹配的方案数
那么显然(ans=sum_{i=0}^{m-1} f_{n,i}),考虑(f)如何转移
假设现在做到(i)的位置,(f_{i-1})显然是已知的,那么就考虑多加入一个数字会带来什么影响
由于这里DP的特性,我们设一个(g_{i,j})表示在不吉利的数字串上匹配时,加入一个数字,能加入多少种,使得长度为(i)的匹配变成长度为(j)的匹配
画画图就会发现原来和准考证号匹配的是前缀,而这里加入的是后缀,因此就是个最大前缀后缀匹配的问题,这就是一个裸KMP啊
然后我们轻易地求出了(g),然后发现这个转移就是个矩乘的形式,因此直接做就好了
#include<cstdio>
#include<cstring>
#define RI register int
#define Ms(f,x) memset(f,x,sizeof(f))
using namespace std;
const int R=25;
struct Matrix
{
int n,m,a[R][R];
Matrix(int N=0,int M=0) { n=N; m=M; Ms(a,0); }
inline void Cir_init(void)
{
for (RI i=0;i<n;++i) a[i][i]=1;
}
}; int n,m,mod,next[R],ans; char s[R];
inline void KMP(void)
{
int len=0; for (RI i=2;i<=m;++i)
{
while (len&&s[len+1]!=s[i]) len=next[len];
if (s[len+1]==s[i]) ++len; next[i]=len;
}
}
inline void inc(int &x,int y)
{
if ((x+=y)>=mod) x-=mod;
}
inline Matrix operator *(Matrix A,Matrix B)
{
Matrix C(A.n,B.m); for (RI i=0;i<A.n;++i)
for (RI j=0;j<B.m;++j) for (RI k=0;k<A.m;++k)
inc(C.a[i][j],1LL*A.a[i][k]*B.a[k][j]%mod); return C;
}
inline Matrix operator ^(Matrix A,int p)
{
Matrix T(m,m); T.Cir_init();
for (;p;p>>=1,A=A*A) if (p&1) T=T*A; return T;
}
int main()
{
RI i,j; scanf("%d%d%d%s",&n,&m,&mod,s+1); Matrix A(m,m);
for (KMP(),i=0;i<m;++i) for (j=0;j<10;++j)
{
int len=i; while (len&&s[len+1]-'0'!=j) len=next[len];
if (s[len+1]-'0'==j) ++len; inc(A.a[i][len],1);
}
A=A^n; for (i=0;i<m;++i) inc(ans,A.a[0][i]);
return printf("%d",ans),0;
}