[HDU5969]最大的位或

题目

B君和G君聊天的时候想到了如下的问题。
给定自然数\(l\)\(r\) ,选取\(2\)个整数\(x,y\)满足\(l \leq x \leq y \leq r\),使得\(x|y\)最大。
其中\(|\)表示按位或,即\(C,C++,Java\)中的\(|\)运算。
Input
包含至多\(10001\)组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数\(l,r\)
保证\(0 \leq l \leq r \leq 1018\)
Output
对于每组数据输出一行,表示最大的位或。
Sample Input
5
1 10
0 1
1023 1024
233 322
1000000000000000000 1000000000000000000
Sample Output
15
1
2047
511
1000000000000000000

解说

题意极其容易理解。
日常习惯先写个暴力试试,意料之中的\(T\)了。没办法,毕竟每次询问都是\(O(n^2)\)
接下来我思路断了,于是瞎试,把\(l\)\(r\)每个数挨个位或一遍,结果所有样例都对上了。于是我开始思考这会不会就是正解?好像确实是呢,位或是只要两个数同一位有一个是\(1\)那么结果就是\(1\),那么我全位或一遍就相当于找了这两个数之间都有哪些位出现了\(1\)。虽然题目问的是找两个数,但稍微想一下就可以发现在这两个数之间是肯定可以找到把出现\(1\)的位都涵盖的两个数的。现在的单次时间效率是\(O(n)\)
\(O(n)\)的时间效率还能过不了?天理难容!交……\(T\)了。
看来要么是还有常数级效率的方法要么就是\(O(logn)\)的方法。常数级不太可能,那么就只能试着把刚才的思想改成\(O(logn)\)的方法,那肯定用到位运算。
和刚才做法等价的做法就是在\(r\)的范围内枚举每一位的\(1\),这样就相当于刚才的找\(1\)操作了。
终于\(A\)了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//记得开long long
ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
} 
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll l,r,tool=1,move=0;//tool就是枚举用的,move表示现在在第几位
        l=read(); r=read();
        while((l|(tool<<move))<=r){
        	l|=(tool<<move);
        	move++;//左移
		}
        printf("%lld\n",l|r);
    }
    return 0;
}

幸甚至哉,歌以咏志。

posted @ 2020-05-05 22:23  DarthVictor  阅读(149)  评论(0编辑  收藏  举报
莫挨老子!