题意:
给一个数串t,再给一个长度len,问长度为len的所有数串中有多少个不包含t(t不是它的子串)。
题解:
设
f[i][j]
表示到第
i
位,前面已经匹配
对于一个状态
f[i][j]
,可以转移到的状态有:
1 .
f[i+1][0]
,后面加入数串后不能与任何前缀匹配。
2.
f[i+1][j+1]
,后面加入数串可以继续匹配。
3.
f[i+1][nxt[pos]+1]
,其中
pos
为
j
,或者与
对于第三种状态相当于是KMP时匹配失败往前跳然后匹配成功,先用kmp预处理
nxt[]
数组,之后发现所有位置的转移都一样(与i无关)。
而且满足矩阵转移公式:
将满足以上转移规则的转移加入对应转移矩阵中(对应 bi 的位置),就可以用矩阵快速幂优化。
#include<bits/stdc++.h>
using namespace std;
int n,m,Mod,nxt[25],vis[25][10];
char ch[25];
struct matrix
{
int a[25][25];
inline void init(int bz)
{
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
this->a[i][j]=0;
if(bz)
{
for(int i=0;i<m;i++)
this->a[i][i]=1;
}
}
friend inline matrix operator *(const matrix &a,const matrix &b)
{
matrix c;c.init(0);
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
for(int k=0;k<m;k++)
(c.a[i][j]+=(a.a[i][k]*b.a[k][j]))%=Mod;
return c;
}
friend inline matrix operator ^(matrix &a,int y)
{
matrix c;c.init(1);
while(y)
{
if(y&1)c=c*a;
a=a*a;
y>>=1;
}
return c;
}
}e,o;
int main()
{
scanf("%d%d%d",&n,&m,&Mod);
scanf("%s",ch+1);
o.a[0][0]=1;
for(int i=0;i<m;i++)e.a[i][0]=9;
for(int i=0;i<m-1;i++)e.a[i][i+1]=1;
for(int i=2,j=0;i<=m;i++)
{
while(j&&ch[i]!=ch[j+1])j=nxt[j];
if(ch[i]==ch[j+1])j++;
nxt[i]=j;
}
for(int i=1;i<m;i++)
{
int pos=i;
do
{
pos=nxt[pos];
if(ch[pos+1]!=ch[i+1]&&!vis[i][ch[pos+1]-'0'])
{
vis[i][ch[pos+1]-'0']=1;
e.a[i][pos+1]++;
e.a[i][0]--;
}
}while(pos!=0);
}
o=o*(e^n);
int res=0;
for(int i=0;i<m;i++)(res+=o.a[0][i])%=Mod;
printf("%d\n",res);
}