题目大意:输入3个数 n,l,u,问你能否找出一个数m,在满足 l <= m <= u的情况下。使得m|n最大,如果有多个数都能使得m最大,那么输出最小的那个数。
解析:直接暴力求解肯定tle,所以这题要用贪心+位运算。
从二进制的高位到低位扫描,
(1)如果当前n的二进制位为1,尽量让m该位变为0,但是如果当前二进制位置为1都小于l,则该位置保持1。
解析:直接暴力求解肯定tle,所以这题要用贪心+位运算。
从二进制的高位到低位扫描,
(1)如果当前n的二进制位为1,尽量让m该位变为0,但是如果当前二进制位置为1都小于l,则该位置保持1。
(2)如果当前n的二进制位为0,尽量让m该位变为1,前提是要让当前的二进制位为1,小于u,否则该位置为0。
注意:如果移位运算时1要写成1ll,不然会爆表。
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
int main() {
ll n,l,u;
while(scanf("%lld%lld%lld",&n,&l,&u) != EOF) {
ll min,ans = 0;
int len = ceil(log2(u));
for(int i = len; i >= 0; i--) {
min = ans + (ll)(1ll << i);
if((n >> i) & 1) { //如果当前该位置为1,尽量让ans该位置为0
if(min <= l) { //但是如果当前位置为1都小于l,则该位置保持1
ans = min;
}
}else { //如果当前位置为0,尽量让ans该位置为1
if(min <= u) { //前提是当前位置为1,小于u
ans = min;
}
}
}
printf("%lld\n",ans);
}
return 0;
}