一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情。
题目描述
Problem - H. Maximal AND
Let AND denote the bitwise AND operation, and OR denote the bitwise OR operation.
You are given an array a of length n and a non-negative integer k. You can perform at most k operations on the array of the following type:
Select an index i (1≤i≤n) and replace ai with ai OR 2j where j is any integer between 0 and 30 inclusive. In other words, in an operation you can choose an index i (1≤i≤n) and set the j-th bit of ai to 1 (0≤j≤30). Output the maximum possible value of a1 AND a2 AND … AND an after performing at most k operations.
Input
The first line of the input contains a single integer t (1≤t≤100) — the number of test cases. The description of test cases follows.
The first line of each test case contains the integers n and k (1≤n≤2⋅10^5, 0≤k≤10^9).
Then a single line follows, containing n integers describing the arrays a (0≤ai<2^31).
It is guaranteed that the sum of n over all test cases does not exceed 2⋅10^5.
Output
For each test case, output a single line containing the maximum possible AND value of a1 AND a2 AND … AND an after performing at most k operations.
Example
input
4
3 2
2 1 1
7 0
4 6 6 28 6 6 12
1 30
0
4 4
3 1 3 1
output
2
4
2147483646
1073741825
Note
For the first test case, we can set the bit 1 (21) of the last 2 elements using the 2 operations, thus obtaining the array [2, 3, 3], which has AND value equal to 2.
For the second test case, we can't perform any operations so the answer is just the AND of the whole array which is 4.
问题解析
这题意思是说,多组数据,每次给你一个数k和一个数组,你每次可以给一个数的二进制位改成1(即 或运算 一个2的x次幂,x最小是0最大是30),一个可以操作k次,问最后这个数组的&运算结果最大可以是多少。
首先,如果是取&运算,我们从二进制的角度来说,要想一个位置的数是1,那么这个数组所有的数这个位置上都应该要是1才行,有一个0都不行。其次,我们想要最后&运算的结果越大,那么就应该从最高位开始(贪心)逐步加到最低位。
我们可以先存下数组在二进制位上的个数,然后看这个位置上的数是否大于等于n(数组长度),如果个数大于等于n,说明数组中每个数的这个二进制位上都是1。举个例子来说,数组是:4 6 7,二进制情况是100,110和111,各个位置上1的数量分别是3、1、1,只有第三位的1满足条件,所以最后进行&运算,这个位置我们是能得到的,其它位置得不到,所以结果就是4。现在我们可以进行k次操作,把某个位置上的1的个数加上k次(也不必要加这么多),比如还是上面的例子,我们现在能进行2次操作,那我们就应该把第二个位置的1个数+2,这样不止第三个位置,第二个位置的1我们也能拿下,这样结果最大就是6了。
所以我们从第30个位置开始枚举(k能修改的位置最大是30),然后看那个位置1的个数+k能否大于等于n,如果可以就说明这位置我们能拿下,然后k的个数减去这次操作消耗的个数,就这样从第30个位置枚举到第一个位置即可。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
vector<ll>v(n);
map<int, int>mymap;
for (int i = 0; i < n; i++)
{
cin >> v[i];
for (int j = 30; j >= 0; j--)
{
if (v[i] & (1 << j))
mymap[j]++;
else mymap[j] += 0;
}
}
ll res=0;
for (int i = 30; i >= 0; i--)
{
if (mymap[i] + k >= n)
{
res |= (1 << i);
k -=(n- mymap[i]);
}
}
cout << res << endl;
}
return 0;
}