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取余的结果。
Input
第一行输入n,m,K,接下来一行输入m 位的数。
Output
模K取余的结果。
对100%的数据满足n<=10^9,m<=20,K<=1000;
题解
首先我们考虑最直接的递推
设
Fi,j
表示两边分别匹配到i位置,j位置
fi,j=∑fi−1,k∗cank,j
其中,
can[k,j]
就是当匹配了k个位置的时候,再在原数后任意加一位数有多少方案能匹配j位
注意:在矩阵中表示,两个下标顺序要小心。
can数组怎么求呢?
你猜
假设现在情况是这样的,已经匹配了J位。
然后呢,我们在A后面加一位
这个匹配位数的转移一定是这样的
fi,j−>fi+1,k
那么这里的K能等于多少呢?
其实就是求X的黑色部分的相等前后缀(包括本身与空串)且这个前缀的后一位=?,那么K就等于这个前缀的长度+1了。
这一步可以枚举下一个数(0~9),用KMP中的求相等前后缀的思想解决
然后就矩阵乘法+快速幂优化
被坑了的地方
扫了一遍题目,然后一位是X的后k位和A的后k位匹配。。 MD,想了半天然后拍断大腿
code
type
matrix=array[0..20,0..20] of longint;
var
fri,ans:matrix;
max,a:array[0..20] of longint;
n,m,mo,k,i,j:longint;
function mamult(a,b:matrix):matrix;
var i,j,k,q:longint;
begin
fillchar(mamult,sizeof(mamult),0);
for k:=0 to m-1 do
for i:=0 to m-1 do
for j:=0 to m-1 do
begin
mamult[k,i]:=(mamult[k,i]+a[k,j]*b[j,i]) mod mo;
end;
end;
function qsm(m:longint;t:matrix):matrix;
var i:longint;
tt:matrix;
begin
dec(m);
tt:=t;
while m>0 do
begin
if m and 1=1 then
t:=mamult(t,tt);
tt:=mamult(tt,tt);
m:=m shr 1;
end;
exit(t);
end;
procedure init;
var c:char;
l:longint;
begin
assign(input,'1115.in'); reset(input);
readln(n,m,mo);
for i:=1 to m do
begin
read(c);
a[i]:=ord(c)-48;
end;
for i:=2 to m do
begin
l:=max[i-1];
while (l<>0)and(a[l+1]<>a[i]) do l:=max[l];
if a[l+1]=a[i] then max[i]:=l+1;
end;
for i:=0 to m-1 do
for j:=0 to 9 do
begin
l:=i;
while (l<>0)and(a[l+1]<>j) do l:=max[l];
if a[l+1]=j then inc(l);
if (l<m) then inc(fri[l,i]);
end;
end;
begin
init();
fri:=qsm(n,fri);
for i:=0 to m do inc(k,fri[i,0]);
writeln(k mod mo);
end.