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
1000000000000000000c++
題意極其容易理解。
平常習慣先寫個暴力試試,意料之中的\(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; }
幸甚至哉,歌以詠志。spa