zoukankan      html  css  js  c++  java
  • 【BZOJ3107】[CQOI2013] 二进制a+b(构造)

    点此看题面

    大致题意: 给定三个数(a,b,c),把它们转化为无前导(0)的二进制数,然后以位数最高的数为基准,给其余数加前导(0)补齐。接下来让你将(a,b,c)二进制下各位重排得到(a',b',c'),使得(a'+b'=c'),求最小的(c')

    构造

    一道构造题,大量分类讨论.......

    我们设(ta,tb,tc)分别表示(a,b,c)二进制下(1)的个数,(l)表示最高的位数。

    方便起见,我们强制(tale tb)

    显然,当(ta+tb=tc)时,答案在二进制下就是连续(tc)(1)

    否则,我们考虑做二进制下加法,每一次进位,(1)的总数便会减少(1)个。

    所以,如果(ta+tb<tc),就肯定无解。

    不然,(ta+tb>tc),则我们设(t=ta+tb-tc),即所需进位的次数。

    然后就是分类讨论了。

    分类讨论

    (tage t)(tbge t)时,我们可以从(a,b)中各拎出(t)(1),把它们放在一起做加法,就实现了进位(t)次。这个运算的结果在二进制下就是(t)个连续的(1)和一个(0)

    然后,(a,b)中分别剩下了(ta-t)(tb-t)(1),由于我们不能让它再进位,所以就必须将它们错开做加法。这个运算的结果就是(ta+tb-2 imes t)(1)

    也就是说,最后的答案将由(t)个连续的(1)和一个(0)(ta+tb-2 imes t)(1)两部分组成。

    由于要让答案最小,所以我们尽量让(0)靠左。

    而且,容易发现答案的总位数是((t+1)+(ta+tb-2 imes t)=ta+tb-t+1=tc+1)

    假设从右边开始首位为第(1)位,则最后答案中为(1)的区间就是:

    [[1,ta+tb-2 imes t],[ta+ta-2 imes t+2,tc+1] ]


    (ta<t)(tbge t)时,首先把(a)中的(1)全部拎出来,再从(b)从同样拎出(ta)(1)和它配合在一起做加法进位(ta)次。

    但由于(ta<t),所以此时进位次数还不够,因此我们需要再从(b)中拎出(t-ta)(1)放在这(ta)(1)左侧,这样一来,(ta)(1)经过加法进位后得到的最高位的那个(1)就会连带地让这(t-ta)(1)全部进位。这个运算的结果在二进制下就是一个(1)(t-ta)(0)(ta-1)(1)和一个(0)

    (tb)中我们一共拎出了(ta+(t-ta)=t)(1),也就是还剩下(tb-t)(1)

    同样容易发现,答案的总位数是(1+(t-ta)+(ta-1)+1+(tb-t)=tb+1)

    像前一种情况一样,由于要尽量让(0)靠左,所以最后答案中为(1)的区间就是:

    [[1,tb-t],[tb-t+2,tb-t+ta],[tb+1,tb+1] ]


    (ta<t)(tb<t)时,发现如果按之前的方法去做就无法凑成(t)次进位。

    假设我们需要从(a,b)中各拎出(x)(1)让它们成对进位,而将(a,b)中剩下的(1)按照前面第二种情况中的方法连带进位,则就有:(x+(ta-x)+(tb-x)ge ta+tb-tc)。化简得到(xle tc)

    而根据(ta<t),即(ta<ta+tb-tc),得到(tb>tc),同理也能得到(ta>tc)

    所以,(x)一定能够取到(tc),且显然(x)越大答案越优(因为凑成的对数越多,答案的位数就越少)。

    我们从(a,b)中各拎出(tc)(1),然后把剩下的(ta+tb-2 imes tc=t-tc)(1)一股脑地堆在这(tc)(1)的左侧。

    加法后,就得到一个(1)(t-tc)(0)(tc-1)(1)和一个(0)

    所以,最后答案中为(1)的区间就是:

    [[2,tc],[t+1,t+1] ]


    顺便提一下,在之前的做法中有可能最后得到的(c')二进制下位数超过(l),显然与题意不符。

    因此我们最后要判断(c'<2^l),才能输出答案。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define swap(x,y) (x^=y^=x^=y)
    #define Fill(x,y) for(i=x;i<=y;++i) ans|=1<<(i-1)
    using namespace std;
    int a,b,c;
    int main()
    {
    	RI i,ta=0,tb=0,tc=0,l;scanf("%d%d%d",&a,&b,&c);
    	for(i=a;i;i&=i-1) ++ta;for(i=b;i;i&=i-1) ++tb;for(i=c;i;i&=i-1) ++tc;//统计1的个数
    	for(ta>tb&&swap(ta,tb),l=1;(1LL<<l)<=max(a,max(b,c));++l);//注意一定要1LL,否则2^31会挂掉
    	RI ans=0,t=ta+tb-tc;if(ta+tb==tc) {Fill(1,tc);goto End;}//以下是各种分类讨论
    	if(t<0) return puts("-1"),0;
    	if(ta<t&&tb<t) {Fill(2,tc);Fill(t+1,t+1);goto End;}
    	if(ta<t) {Fill(1,tb-t);Fill(tb-t+2,tb-t+ta);Fill(tb+1,tb+1);goto End;}
    	Fill(1,ta+tb-2*t);Fill(ta+tb-2*t+2,tc+1);
    	End:return ans<(1LL<<l)?printf("%d
    ",ans):puts("-1"),0;//最后输出答案前记得判断
    }
    
  • 相关阅读:
    前端代码规范
    node服务通过Jenkins上线流程
    移动端常用布局方法
    前端工程化
    前端开发辅助
    前端Node项目发布流程
    观list.clear()方法 有感
    数据导出 写入到excle文件
    tomcat内存使用情况
    三种分布式锁 简易说说(包含前一篇提到的redis分布式锁)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3107.html
Copyright © 2011-2022 走看看