• 2019.08.06模拟赛T2


    题目大意:

    已知三个$n$位二进制数$A$,$B$,$C$.

    满足:

    $A+B=C$

    它们二进制位中$1$的个数分别为$a$,$b$,$c$.

    求满足条件的最小的$C$.

    Solution

    唉,又是一道随缘猜结论的题,可惜极限数据卡掉了我一个点,开大数组就A了.....

    通过$n leq 10$的打表,我们发现所有的最优解中都有一种情况是$A$的二进制位的$1$是连续一段。

    事实上,真的就是这样的!

    设$t=a+b-c$,显然,$t$表示加法过程中进位的次数。

    我们设$A$的$a$个$1$是连续的,然后在$B$中添加$b$个$1$,使得其刚好进位了$t$次(这里$a$个一后面可能有后导$0$)。

    然后要分两种情况讨论。

    $1.ageq t$

    $A:00001111cdots11$

    那么$B$在填$1$的时候,就不能填在$A$中最后一个$1$的位置,因为那样进位次数就会超过$t$.

    所以第一个$1$应该填在这里,且$B$的前面也只能是$0$,否则相加时还会继续进位:

    $A:0000underbrace{111cdots1}_{t}1111cdots$

    $B:$      $0$            $10000cdots$

    那么,剩下的那些$1$,就可以填在中间的位置,直到填满为止,这样就保证了$C$的尽量小。

    如果中间还没填满,那就可以完事了。

    接着考虑中间填满的情况,而且$B$中还有$1$没填:

    $A:0000underbrace{11111cdots1}_{t}1111cdots$

    $B:$       $011111cdots10000cdots$

    这里$B$还有两种可以填的地方,前面或后面。

     事实上,通过推一推式子,我们发现剩下的$1$放在$B$的后面,然后$A$的后面补$0$才可以使$C$最小。

    具体来说,就是设$x$为$B$中放后面的$1$的个数,然后求出$C$关于$x$的函数$f(x)$,然后发现$x$越大,$C$就越小,因此应该剩下的$1$全放在后面。

    举个例子,$a=4,b=4,c=6,t=2$,构造出来应该是这样的:

    $A:0111100$

    $B:0110011$

    $C:1101111$

    $2.a<t$

    这时为了使进位次数刚好为$t$次,所以$B$的首个$1$应填在$A$中最后一个$1$的位置。

    然后为凑齐$t$次,还得在前面补$1$,像这样:

    $A:000cdots011111cdots11$

    $B:0000111cdots000cdots1$

    接下来的话同理,$B$中剩下的$1$先填在中间的空位,若未填满则结束,否则$1$放在后面,同时$A$在后面补$0$。

    当然,代码就很好写(毒瘤)了:

    #include<bits/stdc++.h>
    #define N 200010
    using namespace std;
    int n,a,b,c,t,ans[N],A[N],B[N];
    void solve()
    {
        if(t>a)
        {
            if(t>=b)
            {
                for(int i = 1;i<=a;i++)A[i] = 1;
                for(int i = 1;i<=c;i++)B[i] = 1;
                for(int i = a+1;i<=t;i++)B[i] = 1;
            }else
            {
                for(int i = 1;i<=b;i++)B[i] = 1;
                for(int i = b-t+1;i<=c;i++)A[i] = 1;
            }
        }else
        {
            if(t>=b)
            {
                for(int i = 1;i<=a;i++)A[i] = 1;
                for(int i = a-t+1;i<=c;i++)B[i] = 1;
            }else
            {
                int x = b-t;
                for(int i = x+1;i<=c;i++)A[i] = 1;
                for(int i = 1;i<=x;i++)B[i] = 1;
                for(int i= c-t+1;i<=c;i++)B[i] = 1;
            }
        }
        for(int i = 1;i<=n;i++)
        {
            ans[i]+=A[i]+B[i];
            if(ans[i]>1)ans[i]-=2,ans[i+1]++;
        }if(ans[n+1])puts("-1"),exit(0);
        for(int i = n;i>=1;i--)printf("%d",ans[i]);
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&a,&b,&c);
        t = a+b-c;
        solve();
        return 0;
    }
    View Code
  • 相关阅读:
    android操作数据库
    Android读写SD卡上的文件
    第四章 函数与程序结构
    getchar()与EOF
    NULL, '',0 '0'的区别
    TCPL 行计数
    行计数
    getchar()用法
    在C语言中,double、long、unsigned、int、char类型数据所占字节数
    队列——解密QQ号
  • 原文地址:https://www.cnblogs.com/ldysy2012/p/11311281.html
Copyright © 2020-2023  润新知