题目梗概
给出一个不吉利数字 A1A2...Am(0<=Ai<=9)有M位 。
求有多少个n位数满足不包含不吉利数字。
解题思路
读完题目便能想到一个显然的数位DP, F[i][j] 表示长度为i,有长度为j的后缀与不吉利数字匹配。
考虑如何转移。
发现所有失配到j的状态都可以转移,所以要提前用KMP构造,假设我们构造出矩阵T。
但是发现还是超时。
接下来我们考虑这么修正答案:
[f[i][0],f[i][1],f[i][2]...f[i][m−1]]=[f[i−1][0],f[i−1][1],f[i−1][2]...f[i−1][m−1]]∗T
这个显然可以用矩阵快速幂优化。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=25;
int n,m,tt,nxt[maxn],sum;
char s[maxn];
struct jz{
int n,m,x[maxn][maxn];
}T,ans;
void make_nxt(){
for (int i=2,j=0;i<=m;i++){
while (j&&s[j+1]!=s[i]) j=nxt[j];
if (s[j+1]==s[i]) j++;
nxt[i]=j;
}
}
jz mul(jz a,jz b){
jz c;memset(c.x,0,sizeof(c.x));
c.n=a.n;c.m=b.m;
for (int i=0;i<c.n;i++)
for (int j=0;j<c.m;j++)
for (int k=0;k<a.m;k++)
c.x[i][j]=(c.x[i][j]+a.x[i][k]*b.x[k][j])%tt;
return c;
}
jz qsm(jz x,int b){
jz c;memset(c.x,0,sizeof(c.x));
c.n=x.n;c.m=x.m;
for (int i=0;i<=c.n;i++) c.x[i][i]=1;
while(b>0){
if (b%2==1) c=mul(c,x);
x=mul(x,x);
b>>=1;
}
return c;
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
scanf("%d%d%d",&n,&m,&tt);
scanf("%s",s+1);
make_nxt();
T.n=T.m=m;
for (int i=0;i<m;i++)
for (char j='0';j<='9';j++){
int k=i;
while(k&&s[k+1]!=j) k=nxt[k];
if (s[k+1]==j) k++;
if (k<m) T.x[i][k]=(T.x[i][k]+1)%tt;
}
ans.n=1,ans.m=m;ans.x[0][0]=1;ans=mul(ans,qsm(T,n));
for (int i=0;i<m;i++) sum=(sum+ans.x[0][i])%tt;
printf("%d\n",sum);
return 0;
}