题目大意:给出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\n", solve(l, r)); } return 0; }
uva10718 - Bit Mask(贪心)
时间: 2024-09-19 11:17:05