题目大意:给出32位无符号的整数n ,给定边界L和R,要求在这个边界里面找出一个整数,它和N做或运算得到的值最大。
解题思路:要求做或运算得到的值最大,先N化成2进制的数,然后要使得结果最大的话,最好的就是【L,R】里面的某个数M能和N二进制数01互补.
比如: 00000111
那么M最好就是 11111000
当然这个M须要满足【L,R】内。
思路是M先先等于L,将L也转换成二进制数,然后和N的二进制,每一位都进行推断。
假设N的某i位上面是0,而M上相应的位也是0,那么能够考虑将M上的这一位变成1,可是的推断是否M在【L,R】区间内,假设超过了,那么另一种可能就是为了保全这个位而将后面的位置为0,这种M与N的结果肯定必保留后面的位的结果要大。
假设N上的某i位是1,而M上相应的也是1,那么依据题意要最小的M,这里就能够考虑能否去掉这个1,相同也是要保证在LR之间,假设较小了,也还是有一种策略:为了使得M的值更小,而且i位的结果仍然不变,能够将这一位1去掉,而将后面的全部的位全置为1。这样尽管后面可能有不须要的1,可是这个能够后面处理。
一个0一个1就是最好的状态了,不用处理。
要用 long long 。
代码:
#include <stdio.h> #include <string.h> const int N = 32; typedef long long ll; ll t[N]; bool w1[N], w2[N]; //打表 二进制数每一位的单位 void init () { t[0] = 1; for (int i = 0; i < N - 1; i++) t[i + 1] = t[i] * 2; } //拆分成二进制数 void cut (ll n, bool w[]) { for (int i = N - 1; i >= 0; i--) { if (n >= t[i]) { w[i] = 1; n -= t[i]; } } } ll solve (ll l, ll r) { ll ans = l; for (int i = N - 1; i >= 0; i--) { if (!w1[i] && !w2[i]) { //都是 0 if (ans + t[i] <= r) ans += t[i]; else { ll temp = 0; for (int j = i - 1; j >= 0; j--) //计算后面的位是1的 if (w2[j]) temp += t[j]; if (ans + t[i] - temp >= l && ans + t[i] - temp <= r) { ans = ans + t[i] - temp; for (int j = i - 1; j >= 0; j--) w2[j] = 0; } } } if (w1[i] && w2[i]) { //都是1 if (ans - t[i] >= l) ans -= t[i]; else { ll temp = 0; for (int j = i - 1; j >= 0; j--) //计算后面位是0的 if (!w2[j]) temp += t[j]; if (ans - t[i] + temp >= l && ans - t[i] + temp <= r) { ans = ans - t[i] + temp; for (int j = i - 1; j >= 0; j--) w2[j] = 1; } } } } return ans; } int main () { ll n, l, r; init(); while (scanf ("%lld%lld%lld", &n, &l, &r) != EOF) { memset(w1, 0, sizeof(w1)); memset(w2, 0, sizeof(w2)); cut(n, w1); cut(l, w2); printf ("%lld ", solve(l, r)); } return 0; }