Description
申准备报名参加GT考试,准考证号为n位数X1X2X3…Xn-1Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数字A1A2A3…Am-1Am(0<=Ai<=9)有m位,不出现是指X1X2X3…Xn-1Xn 中没有恰好一段等于A1A2A3…Am-1Am。A1和X1可以为0。
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果。
对100%的数据满足n<=10^9,m<=20,K<=1000;
Solution
明显可以考虑DP
设
f[i,j]
表示当前枚举到第
i
位,在
我们发现,对于每一种
转移过来的状态其实就是KMP匹配的上一位。
既然与
Code
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define M 22
using namespace std;
struct node
{
int a[M][M];
}a,s;
int n,m,mo,num[M],p[M];
node ti(node a,node b)
{
node c;
memset(c.a,0,sizeof(c.a));
fo(i,0,m)
fo(j,0,m)
{
c.a[i][j]=0;
fo(k,0,m) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
}
return c;
}
node ksm(node k,int n)
{
if(n==1) return k;
node s=ksm(k,n/2);
return(n%2)?ti(s,ti(s,k)):ti(s,s);
}
void kmp()
{
int j=0;
p[1]=0;
fo(i,2,m)
{
while(num[j+1]!=num[i]&&j>0) j=p[j];
if(num[j+1]==num[i]) j++;
p[i]=j;
}
}
int main()
{
cin>>n>>m>>mo;
scanf("\n");
fo(i,1,m)
{
char ch;
scanf("%c",&ch);
num[i]=ch-'0';
}
kmp();
fo(i,0,m-1)
{
fo(j,0,9)
{
int q=i;
while(num[q+1]!=j&&q>0) q=p[q];
if(num[q+1]==j) q++;
s.a[i][q]++;
}
}
a.a[0][0]=1;
a=ti(a,ksm(s,n));
int ans=0;
fo(i,0,m-1) ans=(ans+a.a[0][i])%mo;
cout<<ans;
}