单串匹配显然用(kmp)
一个暴力的dp是设(f_{i,j}),表示前(i)位,正在匹配给定串第(j)位的方案,转移就枚举下一位放什么,然后使用(kmp)看会匹配到给定串的哪位
但是(n)非常大,注意到(f_{i,j}->f_{i+1,k})这样的转移可以抽象为一条从(j)到(k)的边,并且(m)很小,于是可以用匹配的关系构建出邻接矩阵,然后矩乘救星了
不会矩乘优化dp的话可以做下这道题
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-7)
using namespace std;
const int N=22;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int mod;
struct martix
{
int n,m;
int a[N][N];
martix(){}
il void init()
{
for(int i=0;i<n;i++) a[i][i]=1;
}
martix(int n,int m):n(n),m(m)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
a[i][j]=0;
}
martix operator * (const martix &b) const
{
martix a=*this,an(a.n,b.m);
for(int i=0;i<a.n;i++)
for(int j=0;j<a.m;j++)
for(int k=0;k<b.m;k++)
an.a[i][j]=(an.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
return an;
}
martix operator ^ (const LL &bb) const
{
martix a=*this,an(a.n,a.m);
an.init();
LL b=bb;
while(b)
{
if(b&1) an=an*a;
a=a*a;
b>>=1;
}
return an;
}
};
char cc[N];
int nxt[N];
int n,m;
int main()
{
n=rd(),m=rd(),mod=rd();
martix a(m,m),b(m,m);
scanf("%s",cc);
for(int i=1,k=0;i<m;i++)
{
while(k&&cc[i]!=cc[k]) k=nxt[k];
nxt[i+1]=(cc[i]==cc[k])?++k:0;
}
for(int i=0;i<m;i++)
{
for(int j=0;j<=9;j++)
{
int k=i;
while(k&&cc[k]!=j+'0') k=nxt[k];
k+=(cc[k]==j+'0');
++b.a[i][k];
}
}
a.a[0][0]=1;
a=a*(b^n);
int ans=0;
for(int i=0;i<m;i++) ans=(ans+a.a[0][i])%mod;
printf("%d
",ans);
return 0;
}