• 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.
    
  • 相关阅读:
    在现有项目中使用AspNet Identity 2.0 实战
    SQL 带自增长列的表的插入
    在C++中子类继承和调用父类的构造函数方法
    C++继承
    C++中重载、重写(覆盖)和隐藏的区别实例分析
    C++类
    C++中头文件(.h)和源文件(.cpp)都应该写些什么
    C++模板
    C语言字符串操作总结大全
    C++ 标准模板库(STL)
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148366.html
Copyright © 2020-2023  润新知