2022-04-24每日刷题打卡

2022-04-24每日刷题打卡

代码源——每日一题

最后的舞会 - 题目 - Daimayuan Online Judge

老师为即将毕业的同学们准备了一场舞会,有2N个同学会参加这场舞会,他们会被分成N对跳舞,每个人有一个编号,如果编号为i的同学和编号为j的同学配对,那么这一对的满意度是Ai,j(i<j),我们规定这个舞会的满意度为每一队的满意度的异或和,也就是说,当同学们分成N组后,第i对同学的满意度为Ai,那么舞会的满意度为A1⊕A2⊕…AN
请你求出本场舞会满意度的最大值

输入描述

第一行给出一个数N,有2N个人参加舞会

接下来给出一个矩阵表示i和j配对时的满意度

A1,2,A1,3,…A1,2N
A2,3,…A2,2N
. . .
A2N−1,2N
其中1≤N≤8,0≤Ai,j≤2^30

输出描述

输出本场舞会满意度的最大值

样例输入
2
4 0 1
5 3
2
样例输出
6
样例解释

如果{1,2},{3,4},ans=A1,2⊕A3,4=4⊕2=6

如果{1,3},{2,4},ans=A1,3⊕A2,4=0⊕3=3

如果{1,4},{2,3},ans=A1,4⊕A2,3=1⊕5=4

最后答案为max(6,3,4)=6

这题可以直接暴力写。

枚举所有的组合,算每次组合的满意度,并在过程中维护最大值。比如你从1开始,选一个和1搭配的,然后再从剩下的人里选一个去做下一队的配对。这里n最多是8,2*n人就是16,此过程每次取一对人出来,那么可能的组合数就是15 *13 *11 *9…… *1,并不会超时。

#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;
const int N = 1e6 + 50, MOD = 100003;
ll n, ans = 0, mx = 0;
vector<vector<ll>>v;
int mymap[20];

inline int read() {
	long long x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}

inline void write(int x) {
	if (x > 9) write(x / 10);
	putchar(x % 10 | '0');
}

void dfs(int u, ll res, int x)
{
	mymap[u] = 1;
	for (int i = u + 1; i <= 2 * n; i++)
	{
		if (mymap[i] == 0)
		{
			ll ans = res ^ v[u][i];
			mymap[i] = 1;
			bool flag = true;
			int j = 1;
			for (; j < 2 * n; j++)
				if (mymap[j] == 0)
					break;
			if (j < 2 * n)
			{
				mymap[j] = 1;
				flag = false;
				dfs(j, ans, x + 1);
				mymap[j] = 0;
			}
			if (flag)
			{
				mx = max(mx, ans);
			}
			mymap[i] = 0;
		}
	}
	mymap[u] = 0;
}

int main()
{
	n = read();
	int  x;
	int m = 2 * n;
	v.push_back({ 0 });
	for (int i = 1; i < m; i++)
	{
		vector<ll>v0(2 * n + 1);
		for (int j = i + 1; j <= m; j++)
		{
			v0[j] = read();
		}
		v.push_back(v0);
	}
	dfs(1, 0, 0);
	write(mx);
	return 0;
}

CodeForces

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值