Time Limit: 1 Sec
Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
Input
第一行输入N,M,K.接下来一行输入M位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
111
Sample Output
81
题解:DP(推出转移方程后就是KMP+矩阵乘法了)
f[i,j]表示到第i位匹配了不吉利数字的多少位。
转移就是从i-1转移,考虑每一个f[i,k]与当前位0~9的组合可以匹配不吉利数字多少位。
最后输出sigma(f[n,k](0<=k<=m-1))。
在转移中如果枚举每一种情况,就会编得很蛋疼。。可是观察发现,这可以看成是一种字符串匹配,所以考虑用KMP。(关于KMP参见Matrix67的blog,查KMP即可)
然后发现,对于每一个i和i-1的转移方程都是相同的,就可以用矩阵乘法优化(关于矩阵优化。。。介个嘛)。
AC CODE
program
hy_1009;
var
T,tt,tmp:
array
[
0..20
,
0..20
]
of
longint
;
a,p,s,f:
array
[
0..20
]
of
longint
;
n,m,kk:
longint
;
//============================================================================
procedure
init;
var
i:
longint
;
ch:
char
;
begin
readln(n,m,kk);
for
i:=
1
to
m
do
begin
read(ch);
a[i]:=ord(ch)-ord(
'0'
);
end
;
end
;
//============================================================================
procedure
KMP;
var
i,x:
longint
;
begin
p[
0
]:=-
1
;
for
i:=
2
to
m
do
begin
x:=p[i-
1
];
repeat
if
a[x+
1
]=a[i]
then
begin
p[i]:=x+
1
; break;
end
; x:=p[x];
until
x=-
1
;
end
;
end
;
//============================================================================
procedure
Set_Matrix;
var
i,j,x:
longint
;
begin
for
i:=
0
to
m-
1
do
for
j:=
0
to
9
do
begin
x:=i;
repeat
if
j=a[x+
1
]
then
begin
inc(T[x+
1
,i]); break;
end
else
if
x=
0
then
inc(T[
0
,i]);
x:=p[x];
until
x=-
1
;
end
;
{for i:=0 to m-1 do
begin
for j:=0 to m-1 do write(T[i,j],' ');
writeln;
end;}
end
;
//============================================================================
procedure
Quick_power(x:
longint
);
var
i,j,k:
longint
;
begin
if
x=
1
then
begin
tt:=T; exit;
end
; Quick_power(x
div
2
);
fillchar(tmp,sizeof(tmp),
0
);
for
i:=
0
to
m-
1
do
for
j:=
0
to
m-
1
do
for
k:=
0
to
m-
1
do
tmp[i,j]:=(tt[i,k]*tt[k,j]+tmp[i,j])
mod
kk;
tt:=tmp;
fillchar(tmp,sizeof(tmp),
0
);
if
x
mod
2
=
1
then
begin
for
i:=
0
to
m-
1
do
for
j:=
0
to
m-
1
do
for
k:=
0
to
m-
1
do
tmp[i,j]:=(tt[i,k]*T[k,j]+tmp[i,j])
mod
kk;
tt:=tmp;
end
;
end
;
//============================================================================
procedure
DP;
var
i,j,ans:
longint
;
begin
s[
0
]:=
9
; s[
1
]:=
1
;
for
i:=
0
to
m-
1
do
for
j:=
0
to
m-
1
do
f[i]:=(f[i]+s[j]*tt[i,j])
mod
kk;
ans:=
0
;
for
i:=
0
to
m-
1
do
ans:=(ans+f[i])
mod
kk;
writeln
(ans);
end
;
//============================================================================
begin
init;
KMP;
Set_Matrix; //建立矩阵。
Quick_power(n-
1
); //转移矩阵的快速幂。
DP;
end
.