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.


posted @ 2019-01-19 20:57  RainbowCrown  阅读(172)  评论(0编辑  收藏  举报