• jzoj3771. 【NOI2015模拟8.15】小 Z 的烦恼


    Description

    小 Z 最近遇上了大麻烦,他的数学分析挂科了。于是他只好找数分老师求情。

    善良的数分老师答应不挂他,但是要求小 Z 帮助他一起解决一个难题问题是这样的,现在有 n 个标号为 1~n 的球和 m 个盒子,每个球都可以放进且只能放进一个盒子里面,但是要满足如下的规则:

    1. 若把标号为 i 的球放进了第 j 个盒子,那么标号为 2*i 的球一定要在第 j+1 个盒子里面(若 j<m)
    2. 若把标号为 i 的球放进了第 j 个盒子,并且 k*2=i,那么标号为 k 的球一定要在第 j-1 个盒子里面(若 j>1)

    小 Z 的数分老师想要知道,给定了 n 和 m 的时候,第一个盒子最多能放进去多少个球。事实上,他已经推算出了公式,但是需要检验当 n 趋向于无穷大时是否仍然满足这个公式,因此 n 可能会非常大。

    Input

    本题包含多组数据,第一行为一个数(T<=20),表示数据组数;以下 T 行,每组数据一行,包括两个数 n 和 m。

    Output

    每组数据输出一行,包括一个数,即第一个盒子最多能放进多少个球。

    Sample Input

    2
    10 2
    10 3

    Sample Output

    4
    1

    Data Constraint

    对于 10%的数据,n<=10^6
    对于 20%的数据,n<=10^9
    对于 30%的数据,m=2
    对于 100%的数据,n<=10^10000,2<=m<=25

    Hint

    样例解释:
    (1).{1,3,4,5}, {2,6,8,10}
    (2).{1},{2},{4}

    题解

    坑题!!!!!
    我用pascal卡常卡了近2小时卡过了,而C++一个臭氧就飞过去了
    what a fine day

    这道题知道结论+高精度/压位+卡常题。
    首先我们考虑把某个数字放到第一位。
    然而我们发现,这样放的话第2个limit是没用的。
    我们就先来一个一个考虑——
    依次放112122122212m11、1*2、1*2*2、1*2*2*2、……、1*2^{m-1}
    依次放222222222222m12、2*2、2*2*2、2*2*2*2、……、2*2^{m-1}(然而这个情况与上面重复,舍去)
    依次放332322322232m13、3*2、3*2*2、3*2*2*2、……、3*2^{m-1}
    依次放442422422242m14、4*2、4*2*2、4*2*2*2、……、4*2^{m-1}(一样重复)
    依次放552522522252m15、5*2、5*2*2、5*2*2*2、……、5*2^{m-1}
    ……
    所以最终只有奇数是可以加入答案的。
    answer+=n2m1+12answer+=frac{frac{n}{2^{m-1}}+1}{2}
    上面什么意思呢?
    由于当:2m1&lt;=n奇数*2^{m-1}&lt;=n满足时,这个奇数就是一种合法的放置方法。
    所以求出奇数个数即可。
    nn=n2m1把n赋个值:n=frac{n}{2^{m-1}}
    当然,放完这些后,12m122m11*2^m……1*2^{2m-1}这一段也是可以放入的。
    于是我们再和上面类似的——
    answer+=n2m+12answer+=frac{frac{n}{2^{m}}+1}{2}
    n=n2m然后:n=frac{n}{2^{m}}
    所以一直递归下去直到n=0时停止即可。
    真是一道奇妙的结论题啊!
    注意压位+卡常

    代码

    type
            new=array[0..1200] of longint;
    var
            i,j,k,l,m,t,ii:longint;
            p,q,op,ok:int64;
            s,n:ansistring;
            answer,nn,x1,c1,c0,c:new;
    
    procedure chu(var n:new;di:longint);
    var
            p,yp:int64;
            i,pp,ypp:longint;
    begin
            if di>1 then
            begin
                    p:=0;
                    for i:=n[0] downto 1 do
                    begin
                            yp:=p;
                            p:=(int64(n[i]+p*1000000000) and ((1 shl di)-1));
                            n[i]:=int64(n[i]+yp*1000000000) shr di;
                    end;
            end
            else
            begin
                    pp:=0;
                    for i:=n[0] downto 1 do
                    begin
                            ypp:=pp;
                            pp:=(int64(n[i]+pp*1000000000) and ((1 shl di)-1));
                            n[i]:=int64(n[i]+ypp*1000000000) shr di;
                    end;
            end;
            while (n[0]>1) and (n[n[0]]=0) do dec(n[0]);
    end;
    
    function plus(a,b:new):new;//inline;
    var
            ii,jj:longint;
    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;
    begin
            readln(t);
            while t>0 do
            begin
                    fillchar(c,sizeof(c),0);
                    dec(t);
                    readln(s);
                    fillchar(answer,sizeof(answer),0);
                    fillchar(nn,sizeof(nn),0);
                    n:='';
                    m:=0;
                    j:=0;
                    for i:=1 to length(s) do
                    begin
                            if (s[i]<>' ') and (j=0) then
                            begin
                                    n:=n+s[i];
                            end
                            else
                            if s[i]=' ' then
                            begin
                                    j:=1;
                            end
                            else
                            if (s[i]<>' ') and (j<>0) then
                            begin
                                    m:=m*10+ord(s[i])-48;
                            end;
                    end;
                    c1[0]:=1;c1[1]:=1;
                    insert(n,nn);
                    chu(nn,m-1);
                    x1:=plus(nn,c1);
                    chu(x1,1);
                    answer:=plus(answer,x1);
                    while (nn[0]>1) or ((nn[0]=1) and (nn[1]>0)) do
                    begin
                            chu(nn,m);
                            x1:=plus(nn,c1);
                            chu(x1,1);
                            answer:=plus(answer,x1);
                    end;
                    print(answer);
                    writeln;
            end;
    end.
    end.
    
    
    
  • 相关阅读:
    记一次线上Kafka消息堆积踩坑总结
    golang Time to String
    转MongoDB 使用Skip和limit分页
    golang mongodb (mgo)插入或读取文档的字段值为空(nil)问题解决
    Golang 中操作 Mongo Update 的方法
    基础知识
    Linux安全之SSH 密钥创建及密钥登录
    ssh配置authorized_keys后仍然需要输入密码的问题
    SSH隧道技术----端口转发,socket代理
    社会信息化环境下的IT新战略
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148371.html
Copyright © 2020-2023  润新知