Description
出乎意料的是,幸运E 的小R 居然赢了那个游戏。现在欣喜万分的小R 想要写一张明信片给小Y,但是因为小R 非常羞涩,所以他打算采用一些比较神奇的方式来表达。
他定义了一些字符串,s1 = a,s2 = b,si =s_i-1 + s_i-2 (i >=3)。同时他定义了一个字符串s 的权值为一个最大的i <|s|满足s 长度为i 的前缀等于长度为i 的后缀。比如字符串aba 的权值就是1,abab 的权值就是2,aaaa 的权值就是3。
现在小R 在明信片上给出了两个数n 和m,他想要告诉小Y 的信息是字符串sn 的前m个字符组成的字符串的权值。你可以帮小Y 计算一下吗?
Input
第一行输入一个正整数T 表示数据组数。
对于每组数据,第一行是两个整数n;m。保证1<= m <=|sn|
Output
对于每组数据,输出一个整数表示答案。答案可能很大,你只需要输出模258280327 后的答案。
Sample Input
2
4 3
5 5
Sample Output
1
2
Data Constraint
对于30% 的数据,n <= 20
对于60% 的数据,n <= 60
对于100% 的数据,n <= 10^3,1 <= T <= 100
题解
首先,我们直接上结论——
当最小的n满足时,答案即为
证明?
我们发现——
那么
接下来我们考虑第二个向右延展的可行性。
也就是当时,向右可否得到后缀与前缀的大小+1.
那么可表示为:
我们发现,从第一行开始数5项与从第二行开始数5项是可以匹配的。
紧接着我们发现,当前只有这个不匹配。
怎么办?
告诉你,可以把这个继续和上面的两个拆,但是无法拆尽。
然而到最后会变成只有最后两个字符不匹配。
所以就会不满足m+1这个条件。
然而把原来的那个n+1变成满足m+1这个条件之后,
又可以继续匹配了。
感性+画图理解理解就可以了。
(其实可以用数学归纳法)
至此,证毕。
最后,只要打个高精度即可。
(我把加减乘除都打上去了,目的就是为了那个逗比的mod)
代码
type
new=array[0..1200] of int64;
var
i,j,k,l,m,t,ii:longint;
p,q,op,ok:int64;
s,nn:ansistring;
kg:char;
answer,n,x1,c1,c2,l1,l2,now,pp,ans1,ans2:new;
function jian(a,b:new):new;
var
ii,jj:longint;
c:new;
begin
fillchar(c,sizeof(c),0);
if a[0]<b[0] then c[0]:=b[0]
else c[0]:=a[0];
for ii:=1 to c[0] do
begin
c[ii]:=c[ii]+a[ii]-b[ii];
if c[ii]<0 then
begin
inc(c[ii],1000000000);
dec(c[ii+1]);
end;
end;
while (c[0]>1)and(c[c[0]]=0) do dec(c[0]);
exit(c);
end;
function plus(a,b:new):new;//inline;
var
ii,jj:longint;
c:new;
begin
fillchar(c,sizeof(c),0);
if a[0]<b[0] then c[0]:=b[0]
else c[0]:=a[0];
for ii:=1 to c[0] do
begin
if c[ii]+a[ii]+b[ii]>1000000000 then
begin
c[ii+1]:=1;
c[ii]:=(c[ii]+a[ii]+b[ii])mod 1000000000;
end
else
c[ii]:=c[ii]+a[ii]+b[ii];
end;
while c[c[0]+1]=1 do
begin
inc(c[0]);
end;
exit(c);
end;
procedure insert(st:ansistring; var x:new);inline;
var
len:longint;
begin
len:=length(st);
while len>=9 do
begin
inc(x[0]);
val(copy(st,len-8,9),x[x[0]]);
dec(len,9);
end;
if len>0 then
begin
inc(x[0]);
val(copy(st,1,len),x[x[0]]);
end;
end;
procedure print(a:new);inline;
var
ii:longint;
begin
write(a[a[0]]);
for ii:=a[0]-1 downto 1 do
begin
if a[ii]<100000000 then write(0);
if a[ii]<10000000 then write(0);
if a[ii]<1000000 then write(0);
if a[ii]<100000 then write(0);
if a[ii]<10000 then write(0);
if a[ii]<1000 then write(0);
if a[ii]<100 then write(0);
if a[ii]<10 then write(0);
write(a[ii]);
end;
end;
function max(a,b:new):boolean;
var
i,j,k:longint;
begin
if a[0]<b[0] then exit(false);
if a[0]>b[0] then exit(true);
for i:=a[0] downto 1 do
begin
if a[i]>b[i] then exit(true);
if a[i]<b[i] then exit(false);
end;
exit(false);
end;
function divv(a:new; b:int64):new;
var
ii:longint;
xx:int64;
c:new;
begin
xx:=0;
fillchar(c,sizeof(c),0);
c[0]:=a[0];
for ii:=a[0] downto 1 do
begin
c[ii]:=xx*1000000000+a[ii];
xx:=c[ii] mod b;
c[ii]:=c[ii] div b;
end;
while (c[0]>1)and(c[c[0]]=0)do dec(c[0]);
exit(c);
end;
function cheng(a,b:new):new;
var
ii,jj:longint;
c:new;
begin
fillchar(c,sizeof(c),0);
c[0]:=a[0]+b[0]-1;
for ii:=1 to a[0] do
for jj:=1 to b[0] do
begin
c[ii+jj]:=c[ii+jj]+(c[ii+jj-1]+a[ii]*b[jj])div 1000000000;
c[ii+jj-1]:=(c[ii+jj-1]+a[ii]*b[jj])mod 1000000000;
end;
while c[c[0]+1]>0 do inc(c[0]);
exit(c);
end;
begin
readln(t);
while t>0 do
begin
dec(t);
fillchar(n,sizeof(n),0);
fillchar(now,sizeof(now),0);
read(m,kg);
readln(nn);
insert(nn,n);
c1[0]:=1;c1[1]:=1;
c2[0]:=1;c2[1]:=258280327;
n:=plus(n,c1);
l1:=c1;l2:=c1;now:=plus(l1,l2);
while not max(now,n) do
begin
pp:=now;
now:=plus(now,l2);
l1:=l2;
l2:=pp;
if now[0]=2 then
begin
j:=j;
end;
end;
n:=jian(n,c1);
ans1:=jian(n,l1);
ans2:=divv(ans1,258280327);
answer:=cheng(ans2,c2);
answer:=jian(ans1,answer);
print(answer);
writeln;
end;
end.