hackerank and-product题目
给定一个自然数区间[a, b],对区间里的所有自然数取与。
输入:8 13
计算:8 & 9 & 10 & 11 & 12 & 13 的结果并输出
介绍一个很简单的O(log(b - a))复杂度的算法:
假设a = 10, b = 13
10 的二进制是 01010
11 的二进制是 01011
12 的二进制是 01100
13 的二进制是 01101
从a递增到b,二进制的变化经过了01100(即12),任何该区间的自然数与12取与首先就会导致结果最后两位为0。然后,因为a和b第3位分别是0和1,取与会导致第3位结果为0。
所以对于一般情况可以这样做:
(1)取b的位长 bit_len
(2)从高位开始检查a和b 同一二进制位是否同为1或0
(3)如果遇到 第k位(从低位算起) 不同,且肯定是a该位为0,b该位为1(因为b>a),从之前你的例子可以看到从a递增到b必定会经过 1000….0(2的k-1次方),与 2的k-1次方 取与会导致结果的 低k-1位 全为0, 且 第k位 也为0
(4)所以最终的结果是 高(bit_len - k)位等于a的高(bit_len - k)位, 低k位全为0 。
代码如下:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int num_case, order;
long long a, b;
scanf("%d", &num_case);
while(num_case--){
scanf("%llu%llu",&a,&b);
order = (int)(log(b) / log(2));
while( ( (a >> order) & 0x01 ) == ( (b >> order) & 0x01 ) ){
order--;
}
printf("%llu\n", (a >> order) << order);
}
return 0;
}