题目链接:http://codeforces.com/contest/578/problem/B
题目大意:现在有n个数,你可以对其进行k此操作,每次操作可以选择其中的任意一个数对其进行乘以x的操作。
思路:最先想到的办法是贪心,也就是选择数组中最大的那个数对它进行k次乘以x的操作。但是这种方法在有的时候会出现错误,如测试数据的第三组:
2 1 2
12 9
这种情况下有2个数,我能够对其进行1次乘以2的操作,如果以之前贪心的方法,选择12乘以2,那么得到的结果(12*2)|9=25,但是如果选择9乘以2,得到的结果是(9*2)|12=30。
考虑12和9的二进制:
12 = (1100)
9 = (1001)
12*2 =(11000)
9*2 =(10010)
12*2|9 =(11001)
9*2|12 =(11110)
可以看到,12*2因为和9在低位因为1|1的数量太多导致了出现12*2|9的结果小于9*2|12的结果,所以说这种贪心的方法是有不正确的地方的。
正确的方法是选择枚举每一个数a[i],计算a[i]*(x的k次方)与其余n-1个数的or和。
这种方法总能找到最优的答案。因为如果我不是选择一个数让他乘上所有的k个x,而是选择了大于1个数让他们分别乘上若干个x,那么在我最开始介绍的让最大的数乘以k个x的贪心方法肯定比这种方法得到更大的结果,因为这种贪心的方法得到的答案的二进制数的最高位一定比拆开来乘得到的二进制的方法得到更大的结果。
我用l[i]表示a[1]到a[i]的or sum,r[i]表示a[n]到a[i]的or sum,delta表示x的k次方,那么我只要枚举每一个l[i-1]|(a[i]*delta)|r[i]就可以了。
参考代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define ll long long const int maxn = 202000; int n, k, x; ll l[maxn], r[maxn], a[maxn], delta; int main() { cin >> n >> k >> x; for(int i=1;i<=n;i++) cin >> a[i]; for(int i=1;i<=n;i++) l[i] = l[i-1] | a[i]; for(int i=n;i>=1;i--) r[i] = r[i+1] | a[i]; delta = 1; for(int i=0;i<k;i++) delta *= x; ll ans = 0; for(int i=1;i<=n;i++) { ll tmp = l[i-1] | (a[i] * delta) | r[i+1]; ans = ans > tmp ? ans : tmp; } cout << ans << endl; return 0; }