ny 744 蚂蚁的难题(一)【位运算】

来源:互联网 发布:南方全站仪数据导出 编辑:程序博客网 时间:2024/06/06 00:33

蚂蚁的难题(一)

时间限制:1000 ms  |  内存限制:65535 KB
难度:2
描述

小蚂蚁童鞋最近迷上了位运算,他感觉位运算非常神奇。不过他最近遇到了一个难题:

给定一个区间[a,b],在区间里寻找两个数x和y,使得x异或y最大。来,帮帮他吧!

输入
有多组测试数据(以EOF结尾)。
每组数据输入两个数a,b.(0<=a<b<2^63)
输出
输出a到b之间,异或最大的值。
样例输入
1 28 9
样例输出
31



第一次见到这个题的时候,感觉有技巧,但是自己没有想到,后来看了别人的提示,想明白了,然后a 了,但是这么简单的题还有必要再多说吗?有!

因为看了网上的代码,虽然他们的代码都不错,但是解释的都不对,至少自己看了好几个人写的所谓规律,没有一个是对的,说错了,不是规律不对,而是表达不对,反正不知道他们是怎么做出来的,或者说是他们在看了别人的代码之后是直接a掉的,也没仔细想,反正我是想了,以下是个人的一些见解,也许会被另外的人说不正确,但是个人认为还是没有问题的:

先说异或的规则:

按位进行异或,那么两个数的运算结果每一位满足同零异一,也就是,每一位相同的话,结果这一位是 0 否则是 1 ,然后看二进制的组成结构,因为二进制逢二进一,只有0 或者 1 来表示,那么在相邻的两个数中,这两个数的最后一位肯定是交替出现0 或者 1 ,类似的也有相似的情况,这里留给大家去研究,下面就是需要探究的问题了,为了异或得到的值最大,那么首先位数要高,那么肯定优先选举位数最大的数,也就是给出的最大的数以及位数相同的几个数,当然,他们只能有一个最优的,只是先定性分析一下,相同的,也尽量选位数最小的一个,呵呵,如果是 0 ,那么就更好了,但是..可惜不是你~所以 只能选择一个位数最小的几个数了,最小的数,位数肯定不会比某个数的大吧,最大的数,位数也不会比某个数小吧?那么这就对了!选择这两个为代表,先求出来这个最优的结果最多有几位!为什么这里可以求出来最高有几位呢?还是很好想的,因为最大的数的 1 肯定想对别的数比较集中在前面,比较小的相对于集中在后面,这样异或下去,虽然不是最优值,但是已经尽量避免了较高位被消去(相同为零),那么求出的数值肯定是和最优解是相同位数的!


然后下面就是其他人理解的规律了,说的不错,因为相邻(或者相差某些二进制位数)的数的 0 和 1 的位置是交替出现的,那么完全可以稍微调整较大和较小的位置来使得异或的结果出现 11111...1111(B),的情况,比如1000(B) 和10(B),他们中的数异或的最大值,位数最多肯定是四位 ,8 的最后一位是 0 ,那么,我们可以把 2 增加一,达到了值变大的目的,然后发现,还可以再把 2 增大一位,变成 7 ,这样就取得最大值了(这个例子只讨论了增大的情况,减小也一样,比如 10 和 2 ) ,不难发现,只要是在位数限制范围内,通过移动,可以实现所有的位置异或的结果出现 1 ,这也就是最后的规律了,然后这个结果可以借助二进制位数来实现,也就是别人所说的 2的n次方 减去 1 ,不过n代表的是最优结果的位数,而不是其他人说的最大值的位数!因为最优解不一定具有和最大值相同的位数,比如 8 9 ,他们异或的最大位数是 1 ,那些随便写博客的人,自己都没真正理解别人的这个做法的由来和原因,完全是照搬别人的代码和解释,也是醉了.......

个人不反对参考别人的思路和解析,但是一定要有自己的理解,如果自己没理解,非要照着别人的写和说的话,无异于自欺欺人,对自己并没有什么用处...个人也是菜鸟,但是自己按着自己的方法来学,会就是会,不会就是不会,这样才是对自己负责的心态....


吐槽结束了.....

有欠缺的地方,希望大家指正!


#include<stdio.h>int main(){long long a,b;while(~scanf("%lld%lld",&a,&b)){long long temp=a^b,maxn=1;while(temp){temp>>=1;maxn<<=1;}printf("%lld\n",maxn-1);}return 0;}



0 0
原创粉丝点击