Codeforces 1632 C. Strange Test —— 位运算,还可以

This way

题意:

给你两个数a,b,你有三种操作:
1.a=a+1
2.b=b+1
3.a|=b
问你最少需要几步才能将a=b。

题解:

好吧我承认是稍微想了一会…或许是因为以前这种题目都是交给队友切的,就想的不是很快,并且感觉应该不是最简单的方法,等博客写完之后去康康别人怎么做的。

这个思路的一个很关键的点在于题目里说了 ∑ b < = 1 e 6 \sum b<=1e6 b<=1e6。所以我们可以枚举最终答案为b~a|b。最多到a|b,否则就可以直接3操作加2操作。
假设现在的答案是i,那么我们肯定是b先加到i,然后a再变成b的子集,再进行或。可能会产生这样的疑问:为什么不在b一开始或者加的过程中a进行或之后,b再加到a的值?
那就不能b加到那个值之后a再或吗,脱裤子放屁增加思考量。
或许会产生一些新的疑问,但可以证明是不需要考虑那些问题的,我自己在做的时候也产生了一些思考。
那么现在要解决的就是,a怎么才能变成i的子集、如果你暴力地去枚举子集的话,TLE。或许有一些新奇的方法,但我使用的是最笨的。对于i比a高的位我们先不考虑,我们考虑a拥有的这些位与i进行异或会是什么结果。因为我们要使得a变成i的子集的步数最少。比如:
i=1101010B
a=   1110B
那么经过操作之后s=100B (意义与代码中相等)
接下来需要去找我们要补到i的哪里。既然是补,那么补完的值肯定要比s大,并且在那一位i的值是1,a的值是0.如果a的值是1的话,那你补上来1的时候不就进位了吗。
就上面这个例子,我们需要将a补成100000B才行。
这看起来和s毫无关系,直接a去补就可以了?考虑这种情况:
i=1101010B
a= 100100B
那么s=100B
这个时候我们是不是只需要将a补成101000B就可以了?所以归根结底s只是规范了下限,具体补到多少还是看a和i的情况。
至于怎么找a走多少步,我是用最笨的方法:假设我们现在要补到t,那么将a中位数>=t的1全部消去,剩下的hav就是我们拥有的值,t-hav就是需要补的值。


挖槽真的烦,不会有人像我一样笨笨的方法吧。

补充:好久没写确实是僵硬了,找不一样的位置直接(a|b)-b不就好了…,找最后一位的话直接lowbit(b-((a|b)-a))…之类的吧,还是要恢复恢复,而且看他们题解里好像直接for一遍b就好了?暂时搞的不是很懂。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int tim;
    scanf("%d",&tim);
    while(tim--){
        int a,b;
        scanf("%d%d",&a,&b);
        int ans=min(b-a,(b|a)-b+1);
        for(int i=b;i<=(b|a);i++){
            int step=i-b;
            int t=1,s=0;
            while(t<=a){
                if(t&a && (t&i)==0)
                    s+=t;
                t<<=1;
            }
            if(s==0){
                ans=min(ans,step+1);
                continue;
            }
            t=1;
            while(t<=s)t<<=1;
            while(t<=i){
                if(t&i && (t&a)==0)
                    break;
                t<<=1;
            }
            int hav=a;
            for(int k=t;k<=a;k<<=1)
                if(k&a)
                    hav^=k;
            ans=min(ans,step+1+t-hav);
        }
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值