[agc015d]A or...or B Problem

前言

一开始想着按二进制位倒着推统计贡献,每次讨论四种情况。
推着推着就发现了结论。
然而还是想复杂了。
直接值域就好了嘛。

题意

用若干个(至少一个)[A,B]中的数进行or操作能得到多少本质不同的数?

做法

先找到A和B最高一个不同的二进制位,设为d。
因为我菜下面我们都假设A是较大数。而且因为我懒接下来都用小写。
我们可以根据第d位是0还是1划分两类数。有1的是第一类数。
我们找到a第二个有1的位置k,我们知道选一堆第一类数进行or在k位之前的位都一样,然后我们发现你可以让一个是10……0,另一个是0?……?,这样可以构造第k位是1剩余随意的数,也可以不要那个10……0。于是我们可以用若干第一类数or出 [2d,2d+2k+11]
然后看第二类数,显然我们可以or出 [b,2d1]
因此我们只用第一类数或第二类数可以or出 [b,2d+2k+11]
如果同时用第一类数和第二类数呢?你可以让第一类数用一个10……0,然后第二类数可以随意但不得小于b,因此可以or出 [2d+b,2d+11] ,然后比较值域取并即可。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
ll two[70],a,b,ans,x,y,u,v;
int i,j,k,l,t,n,m,d;
int main(){
    scanf("%lld%lld",&a,&b);
    swap(a,b);
    two[0]=1;
    fo(i,1,62)  two[i]=(ll)two[i-1]*2;
    fd(i,62,0){
        if ((a&two[i])!=(b&two[i])) break;
        if ((a&two[i])>0){
            a^=two[i];
            b^=two[i];
        }
    }
    if (a==b){
        printf("1\n");
        return 0;
    }
    d=i;
    fd(k,i-1,-1)
        if (k==-1||(a&two[k])>0) break;
    x=b;y=two[d]+two[k+1]-1;
    u=two[d]+b;v=two[d+1]-1;
    ans=y-x+1;
    if (u>y) ans+=v-u+1;
    else if (u<=y&&v>y) ans+=v-y;
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值