Codeforces 1208F Bits And Pieces 位运算 + 贪心 + dp

题意:给你一个序列a, 问a[i] ^ (a[j] & a[k])的最大值,其中i < j < k。

思路:我们考虑对于每个a[i]求出它的最优解。因为是异或运算,所以我们从高位向低位枚举,如果这一位a[i]是0,我们就在a[i]的右边找两个位置让它们按位与起来这位是1。那么,我们贪心的保留可以通过按位与凑出某个二进制数的最靠右的两个位置。这个可以通过dp的方式预处理出来。之后,我们枚举每一个数a[i],先找出它的哪些位是0,之后从高位到低位枚举,判断这一位是否可以变成1。如果之前已经加上的位再加上这一位可以被凑出来,那么我们就加上这一位。在所有的a[i]得出的答案中去最大值即可。

代码:

1#include <bits/stdc++.h> 2#define pii pair<int, int> 3#define INF 0x3f3f3f3f 4#define db double 5using namespace std; 6const int maxn = 2000010; 7pii dp[1 << 21]; 8int a[maxn]; 9void update(int mask, int val) { 10 if(dp[mask].second == 0) { 11 dp[mask].second = val; 12 return; 13 } 14 if(dp[mask].first == val || dp[mask].second == val) return; 15 if(val > dp[mask].second) { 16 dp[mask].first = dp[mask].second; 17 dp[mask].second = val; 18 } else if(val > dp[mask].first) { 19 dp[mask].first = val; 20 } 21} 22void merge(int mask1, int mask2) { 23 if(dp[mask2].first != 0) update(mask1, dp[mask2].first); 24 if(dp[mask2].second != 0) update(mask1, dp[mask2].second); 25} 26int main() { 27 int n; 28 scanf("%d", &n); 29 for (int i = 1; i <= n; i++) { 30 scanf("%d", &a[i]); 31 update(a[i], i); 32 } 33 for (int i = 0; i < 21; i++) { 34 for (int j = 0; j < (1 << 21); j++) { 35 if((j >> i) & 1) { 36 merge(j ^ (1 << i), j); 37 } 38 } 39 } 40 int ans = 0; 41 for (int i = 1; i <= n; i++) { 42 int mask = 0, tmp = (1 << 21) - 1 - a[i]; 43 for (int j = 20; j >= 0; j--) { 44 if((tmp >> j) & 1) { 45 if(dp[mask ^ (1 << j)].first > i && dp[mask ^ (1 << j)].second != 0) { 46 mask ^= (1 << j); 47 } 48 } 49 } 50 if(dp[mask].first > i && dp[mask].second != 0) ans = max(ans, a[i] ^ mask); 51 } 52 printf("%d\n", ans); 53}
点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java中的7个位运算运算符

位运算指的是针对整数的二进制进行的位移操作。位运算提供比算术运算更高的效率,但是位运算的代码可读性较差,建议所有使用位运算的地方写上注释。Java中提供7个位运算符用于位运算。左移(<<)左移运算是将操作数二进制值逐位左移若干位,左移过程中符号位不变,高位溢出则舍弃,低位则补0。范例结果范例结果00000001<<

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

一.二进制,位运算,移位运算1.二进制对于原码,反码,补码而言,需要注意以下几点:(1).Java中没有无符号数,换言之,Java中的数都是有符号的;(2).二进制的最高位是符号位,0表示正数,1表示负数;(3).正数的原码,反码,补码都一样;(4).负数的反码它的原码符号位不变,其他位取反;(5).

OC中的位运算

转载:https://www.jianshu.com/p/b868b30c0c88OC中的位运算和C/C语言的位运算是一样的。一般有&(按位与),|(按位或),~(按位取反),<<(左移),(右移),^(异或)以及&(按位与然后赋值),|(按位或然后赋值)等对枚举类型的操作中常常会见到。例如定义一个季节SeasonT

C语言位运算

位运算应用口诀清零取反要用与,某位置一可用或若要取反和交换,轻轻松松用异或移位运算要点1它们都是双目运算符,两个运算分量都是整形,结果也是整形。        2"<<"左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。       3""右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空

20180109Java位运算

一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由

Codeforces 1208F Bits And Pieces 位运算 + 贪心 + dp - HelloWorld