Codeforces Round 928 (Div. 4)DEF

Codeforces Round 928 (Div. 4)DEF

D. Vlad and Division(位运算)

题意&思路

给n个数组,如果某些数字的二进制下所有位都不一样,那就可以放一组。所以一组最多放两个数字,而且这两个数字异或之后的结果是0111 1111 1111 1111 1111 1111 1111 1111(在某一位上,如果其中一个数字这位上是1,那另一个数字这一位上就只能是0,异或就是1)(然后题目是231,所以第一位不看了)

枚举所有数字,暴力遍历整个数组,看看有没有数字能和它为一组。这样就超时了,所以就可以用map记录一下所有数字出现的数字,不会超时了就

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
const int maxN = 2147483647;
void solve() {
	unordered_map<int, int>mp;
	int n; cin >> n;
	mp.reserve(n);
	vector<int>v;
	for (int i = 0, num; i < n; i++) {
		cin >> num;
		mp[num]++;
		v.push_back(num);
	}
	long long cnt = 0;
	for (int i = 0; i < n; i++) {
		int curNum = v[i];
		if (!mp[curNum])continue;
		int tep = 0;
		if (mp.count(maxN ^ curNum)) {
			tep = min(mp[maxN ^ curNum], mp[curNum]);
			mp[maxN ^ curNum] -= tep;
			mp[curNum] -= tep;
		}
		if (mp[curNum]) {
			tep += mp[curNum];
			mp[curNum] = 0;
		}
		cnt += tep;
	}
	ans.push_back(cnt);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}
// 除了第32位,每一位都不相同,异或结果为 0111 1111 1111 1111 1111 1111 1111 1111
// 如果找不到另外一个这样的数,那就自己一组

E. Vlad and an Odd Ordering(神秘数学题)

题意&思路

设当前为第 i 轮,那么放的数字就是 i * (2k - 1),k表示这一轮放的第 k 个数字。很显然就是要找到每一次放的数字,会不会跟前面的数字重合,找到这个关系

第奇数轮放的数字肯定都是奇数,不用管了(第1轮已经把所有奇数都放完了)

第2轮放的数字是 2 * (2k - 1)

第4轮放的数字是 4 * (2k - 1),是2 * (2 * (2k -1) ),跟第二轮的不会重合(每一个数字都比对应的第2轮的数字大2倍)

第6轮放的数字是 6 * (2k - 1),是6、18、30...,3 * (2 * (2k -1) ) = 2 * (3 * (2k - 1) ),是2乘一个奇数得到的,同时第2轮的数字,都是通过2乘一个奇数得到的,所以第6轮的数字肯定都被第2轮枚举过了

第8轮放的数字是 8 * (2k - 1),在第4轮的基础上再多乘了一个2,同样的每一个对应的数字都比第4轮的数字大2倍

第10轮放的数字是 10 * (2k - 1),= 2 * (5 * (2k - 1) ),是第2轮的数乘一个奇数

第12轮放的数字是 12 * (2k - 1),= 3 * 4 * (2k - 1),显然是在第4轮枚举过的数字里面挑一些数字出来

第14轮放的数字是 14 * (2k - 1),= 2 * (7 * (2k - 1) ),是第2轮的数乘一个奇数

第16轮放的数字是 16 * (2k - 1),在第8轮的基础上再多乘了一个2,同样的每一个对应的数字都比第8轮的数字大2倍

……

我数学垃圾,只能全部列出来看看了,发现就是2次幂的轮次的时候,才是有效的轮次,所以只要计算到那一轮枚举到n就行了

具体计算每轮多少个数字的时候(k最大到多少)(当前在第m次幂(m+1轮))

2m * (2k - 1) <= x

2k - 1 <= x / 2m

2k <= (x + 2m) / 2m

k <= (x + 2m) / 2m+1

k = (floor)(x + 2m) / 2m+1

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;

void solve() {
	long long n, k;
	cin >> n >> k;
	for (long long m = 0; m <= 31; m++) {
		long long tep = (n + (1ll << m)) / (1ll << (m + 1));
		if (k > tep) {
			k -= tep;
		}
		else {
			ans.push_back((1ll << m) * (2 * k - 1));
			return;
		}
	}
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

F. Vlad and Avoiding X(神秘深搜、剪枝)

题意

给7 * 7的网格,包含B和W,要让里面的B不形成 X ,问最少要修改多少B

思路

一看7 * 7,直接爆搜,然后就超时了。无法接受,于是看了别人的说法。把行列和为奇数/偶数的点分开来搜,因为这两种点,无论如何都不会在形成 X 这件事情上影响对方,于是乎相当于把地图缩了一半

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<int>ans;
int dx[] = { -1,-1,1,1,0 };
int dy[] = { -1,1,1,-1,0 };
int res1, res2;

vector<vector<char>>mp(10, vector<char>(10));

bool illgeal(int x, int y) {
	int cnt = 0;
	for (int i = 0; i < 4; i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (0 >= nx || 0 >= ny || nx > 7 || ny > 7)continue;
		if (mp[nx][ny] == 'B')cnt++;
	}
	return cnt == 4;
}

// type是指当前DFS只处理一种类型
void dfs(int x, int y, int cnt, int type) {
	if (x == 7) {
		if (type == 0) {
			res1 = min(res1, cnt);
		}
		else {
			res2 = min(res2, cnt);
		}
		return;
	}
	if (y == 7) {
		dfs(x + 1, 2, cnt, type);
		return;
	}
	if ((x + y) % 2 != type) {
		dfs(x, y + 1, cnt, type);
		return;
	}
	if (mp[x][y] == 'B' && illgeal(x, y)) {
		for (int i = 0; i < 5; i++) {
			mp[x + dx[i]][y + dy[i]] = 'W';
			dfs(x, y + 1, cnt + 1, type);
			mp[x + dx[i]][y + dy[i]] = 'B';
		}
		return;
	}
	dfs(x, y + 1, cnt, type);
}

void solve() {
	res1 = res2 = INT_MAX;
	for (int i = 1; i <= 7; i++) {
		for (int j = 1; j <= 7; j++) {
			cin >> mp[i][j];
		}
	}
	dfs(1, 1, 0, 0);
	dfs(1, 1, 0, 1);
	ans.push_back(res1 + res2);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}
posted @ 2025-04-26 22:23  zombieee  阅读(26)  评论(0)    收藏  举报