l=’0’,r=’1’。每次操作把r变成l+r,把l变成r。求n次操作后,l中子串T的数量mod P
第一行n,m,t,p。m为T的长度。第二行为T
答案mod p
7 3 100
101
8
N<= 109 ,M<=10000,
对于30%,N<= 105
N巨大,显然找规律。
设当前l串中T的个数为a1,r串中为a2,则l+r之后答案为a1+a2+C。C为合并之后的T的个数(T必须穿过合并的那个位置)。或者说C为合并之后中间部分多出来的字串数量。
C只能是l的后M-1和r的前M-1合并后子串的数量。如果任意一个字串超过或等于M,就不能保证C为合并后多出来的数量。
列个表
l r
0 1
1 01
01 101
101 01101
暴力一下l和r,发现当两个串长度都超过M之后,合并后中间两个数为10,11,10,11……,这时C就进入了长度为2的循环。
你会说这里只算了中间两个数,你可以试一试两边都取长一些,会发现C仍然为长度为2的循环。
记为C1,C2。
这下就好办了。
已知a1,a2,C1,C2,之后,可以推出a3=a1+a2+C1,a4=a2+a3+C2,a5=a3+a4+C1……
那么怎么求a1,a2,C1,C2呢?先知道求一个串中指定字串的数量用KMP。具体请看KMP算法详解。
发现M只有10000。那么暴力l和r直到两个串长度都>=M,a1就是当前l中T的个数,a2就是r中T的个数。C1就是l的后M-1位与r的前M-1位合并后得到的串中T的数量。C2就是l的前M-1位与r的后M-1位合并后得到的串中T的数量。接着递推就可以60分了。
还有四十分连O(n)都会超时,那么就用矩阵乘法就行了。
type
arr=array[1..4,1..4] of int64;
arr2=array[1..4] of int64;
var
n,m,x,y,i,j,v1,v2,mo,ans:longint;
s0,s1,ss,s2,s3:ansistring;
next:array[0..100000] of longint;
bz:boolean;
a:arr=((1,1,0,0),
(1,2,0,0),
(1,1,1,0),
(0,1,0,1));
f:arr2;
function kmp(s1,s2:ansistring):longint;
var
i,j,k,n,ans:longint;
begin
j:=0;n:=length(s1);ans:=0;
for i:=1 to n do
begin
while (j>0)and(s1[i]<>s2[j+1]) do begin j:=next[j];end;
if s1[i]=s2[j+1] then inc(j);
if j=m then
begin
inc(ans);
j:=next[j];
end;
end;
exit(ans);
end;
function matrix(a,b:arr):arr;
var
i,j,k:longint;
begin
fillchar(matrix,sizeof(matrix),0);
for i:=1 to 4 do
for j:=1 to 4 do
for k:=1 to 4 do
matrix[i,j]:=(matrix[i,j]+a[i,k]*b[k,j]+mo)mod mo;
end;
function matrix2(a:arr2;b:arr):arr2;
var
i,j,k:longint;
begin
fillchar(matrix2,sizeof(matrix2),0);
for j:=1 to 4 do
for k:=1 to 4 do
matrix2[j]:=(matrix2[j]+a[k]*b[k,j]+mo)mod mo;
end;
function mi(a:arr;b:int64):arr;
var
c:arr;
begin
if b=1 then exit(a);
if b mod 2=0 then
begin
c:=mi(a,b div 2);
exit(matrix(c,c));
end
else
begin
c:=mi(a,b div 2);
exit(matrix(matrix(c,c),a));
end;
end;
begin
assign(input,'4374.in'); reset(input);
//assign(output,'4374.out'); rewrite(output);
readln(n,m,mo);
readln(ss);
j:=0;
if n=1 then begin writeln(0);exit;end;
for i:=2 to m do
begin
while (j>0)and(ss[i]<>ss[j+1]) do j:=next[j];
if ss[i]=ss[j+1] then inc(j);
next[i]:=j;
end;
//-----------
s0:='0';s1:='1';
while n>0 do
begin
s2:=s1;s1:=s0+s1;s0:=s2;
if (length(s0)>=m)and(length(s1)>=m)then break;
dec(n);
end;
f[1]:=kmp(s0,ss);f[2]:=kmp(s1,ss);
s2:=s1;s3:=s0;s1:=copy(s1,1,m-1);delete(s0,1,length(s0)-m+1);
v1:=kmp(s0+s1,ss);
s1:=s3+s2;s0:=s2;s1:=copy(s1,1,m-1);delete(s0,1,length(s0)-m+1);
v2:=kmp(s0+s1,ss);
f[3]:=v1;f[4]:=v2;
a:=mi(a,(n-1) div 2);
f:=matrix2(f,a);
n:=n mod 2;if n=0 then n:=2;
writeln(f[n]mod mo);
close(input);close(output);
end.