这道题贼有意思,是一个二进制的题,当时比赛的时候模模糊糊的有点思路,但是想错了,最后还是粗事情了,我开始的想法不是很清晰,试图打表解决。画个图来表达我的想法吧。
我一开始的想法是一个猜测。
当两个数的差大到一定程度的时候那么它们的&运算的结果肯定是0,|运算的结果肯定是111111111(1的个数为两个数中二进制位数较大的位数);
当然这个猜测的大概方向,可能是靠谱的吧
问题是我没能条理清晰的分析这个猜想
没能深入去推敲这个东东,不然可能当时就做出来了
可能是当时脑子有点懵逼吧
两者单纯的数量差不是关键,关键是两个数的二进制位数差
无标题.png
我自己画的图,挺丑的,但是大概表达了意思,我将从A->B过程中A,B的会进行01交替变化的区域称为活动区,即为图中褐色笔圈出来的部分。活动区的变化结果符合我上面的猜想,|的计算结果每一位都为1,&的计算结果每一位都为0。
那么当A<B时,整个B长度内的区域都为活动区,那么计算结果就是|为lenb长度个1,&为0;
当A==B时活动区为从高位到低位第一个A和B不相同的数字后的区域,那么计算结果也就是|为B在这一位之后的位数全部换为1;&为这一位过后的位数全部换为0;
那么这时候直接再将二进制转换为十进制便是结果:
我的代码如下,我是直接将十进制数字转换为二进制进行操作的,操作完再转回十进制;
当然肯定还有更加巧妙的做法;
但肯定差不多也是基于这个思路和特性;
我的代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
typedef long long LL;
int a[63],b[63];
const LL one = 1;
int change(LL x,int *a)
{
int cnt = 0;
while(x)
{
a[cnt] = x&1;
x >>= 1;
cnt++;
}
return cnt;
}
int main()
{
int t;
scanf("%d",&t);
int cas = 1;
while(t--)
{
LL x,y;
scanf("%lld%lld",&x,&y);
int xx = change(x,a);
int yy = change(y,b);
if(yy>xx)
{
LL t = (one << yy) - 1;
LL Or = t;
LL And = 0;
printf("Case %d: %lld %lld\n",cas++,Or,And);
continue;
}
if(xx == yy)
{
int i;
for(i = yy-1;i>=0;i--)
{
if(a[i]!=b[i])
{
break;
}
}
LL t = (one << (i+1)) - 1;
LL Or = y|t;
LL And = y&~t;
printf("Case %d: %lld %lld\n",cas++,Or,And);
continue;
}
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
}
}
网友评论