jzoj4213. 对你的爱深不见底

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满足Sn&gt;m+1|S_n|&gt;m+1时,答案即为mSn2m-|S_{n-2}|
证明?
我们发现——
Sn=Sn1+Sn2S_n=S_{n-1}+S_{n-2}
那么Sn=Sn2+Sn3+Sn2S_n=S_{n-2}+S_{n-3}+S_{n-2}
Sn=Sn3+Sn4+Sn3+Sn3+Sn4S_n=S_{n-3}+S_{n-4}+S_{n-3}+S_{n-3}+S_{n-4}
Sn=Sn3+Sn4+Sn3+Sn4+Sn5+Sn4S_n=S_{n-3}+S_{n-4}+S_{n-3}+S_{n-4}+S_{n-5}+S_{n-4}
Sn=Sn2+Sn2+Sn5+Sn4S_n=S_{n-2}+S_{n-2}+S_{n-5}+S_{n-4}
接下来我们考虑第二个Sn2S_{n-2}向右延展的可行性。
也就是当m=Sn22m=|S_{n-2}*2|时,向右可否得到后缀与前缀的大小+1.
那么SnS_n可表示为:
Sn5+Sn6+Sn5+Sn4(Sn2)+S_{n-5}+S_{n-6}+S_{n-5}+S_{n-4}(这里前面是S_{n-2}拆出来的式子)+
Sn5+Sn6+Sn5+Sn4+S_{n-5}+S_{n-6}+S_{n-5}+S_{n-4}+
Sn5+Sn4S_{n-5}+S_{n-4}
我们发现,从第一行开始数5项与从第二行开始数5项是可以匹配的。
紧接着我们发现,当前只有这个Sn4S_{n-4}不匹配。
怎么办?
告诉你,可以把这个继续和上面的Sn6S_{n-6}两个拆,但是无法拆尽。
然而到最后会变成只有最后两个字符不匹配。
所以就会不满足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.
原文地址:https://www.cnblogs.com/RainbowCrown/p/11148366.html