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;
}

浙公网安备 33010602011771号