Description
准考证号为 (N) 位数 (X_1,X_2…X_n(0le X_ile9)),他不希望准考证号上出现不吉利的数字。他的不吉利数 (A_1,A_2…A_m(0le A_ile 9)) 有 (M) 位,不出现是指 (X_1,X_2…X_n) 中没有恰好一段等于 (A_1,A_2…A_m),(A_1) 和 (X_1) 可以为 (0)。
Solution
设 (next[i]) 表示 (A[1..i]) 的最长公共真前后缀,可以 KMP 预处理出
构造矩阵,当匹配到 (i) 位置 (+c) 可以转移到 (p) 位置时,对 (mat[p][i]++)
这就是 DP 的转移矩阵,快速幂处理即可
(实际上最后我们只需要统计幂矩阵的第一列的和)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 25;
int n,m,mod;
char s[N];
namespace kmp
{
char *p=s;
int n,m,fail[N];
void main()
{
m=strlen(p+1);
for(int i=2; i<=m; i++)
{
fail[i]=fail[i-1];
while(p[fail[i]+1]-p[i] && fail[i]) fail[i]=fail[fail[i]];
if(p[fail[i]+1]==p[i]) ++fail[i];
}
fail[0]=-1;
}
}
struct matrix
{
int n,a[N][N];
matrix(int n=0):n(n)
{
memset(a,0,sizeof a);
}
int* operator [] (int i)
{
return a[i];
}
friend matrix operator * (matrix a,matrix b)
{
int n=a.n;
matrix res(n);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
res[i][k]=((res[i][k]+a[i][j]*b[j][k])%mod+mod)%mod;
}
}
}
return res;
}
matrix I()
{
matrix res(n);
for(int i=1; i<=n; i++)
{
res[i][i]=1;
}
return res;
}
matrix operator ^ (int b)
{
if(b) return (((*this)*(*this))^(b/2))*(b&1?(*this):I());
return I();
}
void print()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) cout<<a[i][j]<<" ";
cout<<endl;
}
}
};
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>mod>>s+1;
kmp::main();
matrix mat(m);
using kmp::fail;
for(int i=0;i<m;i++)
{
for(char c='0';c<='9';c++)
{
int p=i;
while(p && s[p+1]!=c) p=fail[p];
if(s[p+1]==c) ++p;
++mat[p+1][i+1];
}
}
//mat.print();
mat=mat^n;
//mat.print();
int ans=0;
for(int i=1;i<=m;i++) ans=(ans+mat[i][1])%mod;
cout<<ans<<endl;
}