问题 H: [HNOI2008]GT考试
时间限制: 1 Sec 内存限制: 162 M题目描述
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为
0
输入
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
输出
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
样例输入
4 3 100
111
样例输出
81
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define V 55
#define LL long long
//#define maxn
#define p 123
using
namespace
std;
char
str[V];
int
f[V],n,len,zz,net[V],ans,mod,ss,s[V];
struct
mat
{
int
m[25][25];
mat operator * (
const
mat&x)
{
mat z={0};
for
(
int
i=0;i<len;i++)
for
(
int
j=0;j<len;j++)
for
(
int
k=0;k<len;k++)
z.m[i][j]=(z.m[i][j]+(m[i][k]*x.m[k][j])%mod)%mod;
return
z;
}
mat operator*=(
const
mat&x)
{
*
this
=*
this
*x;
}
}S,W;
inline
void
getnext()
{
memset
(net,0,
sizeof
(net));
for
(
int
i=0;i<len;i++)
s[i+1]=str[i]-
'0'
;
net[0]=net[1]=0;
zz=0;
for
(
int
i=2;i<=len;i++)
{
while
(zz&&str[zz]!=str[i-1])zz=net[zz];
if
(str[zz]==str[i-1])zz++;
net[i]=zz;
}
}
int
main()
{
//freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
//freopen("bzoj_1009.in","r",stdin);freopen("bzoj_1009.out","w",stdout);
cin>>n>>len>>mod;
scanf
(
"%s"
,str);
getnext();
for
(
int
i=0;i<len;i++)
{
for
(
int
j=0;j<=9;j++)
{
ss=i;
while
(ss&&j!=s[ss+1])ss=net[ss];
if
(s[ss+1]==j)++ss;
S.m[i][ss]++;
}
}
W.m[0][0]=1;
while
(n)
{
if
(n&1)
{
W*=S;
}
S*=S;
n>>=1;
}
for
(
int
i=0;i<len;i++)
ans+=W.m[0][i]%mod;
cout<<ans%mod;
return
0;
}