VP Codeforces Round 896 (Div. 2)
A. Make It Zero
题意:给你一个数组,每次操作一个区间,让这个区间的数都变成区间的异或和,操作不能超过8次,使得数组全变成0。
如果数组是偶数,直接操作两次\([1, n]\)就行了。
如果数组是奇数,也是先操作一下\([1, n]\),这时数组都变成了一样的数,然后操作\([1, n - 1]\),前\(n-1\)个就变成0了,然后操作两次\([n - 1, n]\)就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<std::pair<int, int>> ans;
ans.push_back({1, n});
if (n & 1) {
ans.push_back({1, n - 1});
ans.push_back({n - 1, n});
ans.push_back({n - 1, n});
} else {
ans.push_back({1, n});
}
std::cout << ans.size() << "\n";
for (auto & [l, r] : ans) {
std::cout << l << " " << r << "\n";
}
}
B. 2D Traveling
题意:有\(n\)个坐标,前\(k\)个坐标之间可以不费代价的任意行走。如果两个坐标中一个不是前\(k\)个,那么代价就是曼哈顿距离。求\(a\)到\(b\)的最小代价。
两个点直接到达肯定是最短的,经过中间一个点再取终点肯定不优。但现在前\(k\)个点可以互相到达,那么可以选一个到\(a\)最短的点和到\(b\)最短的点,因为这两个点之间不消耗代价,可能更优。
点击查看代码
void solve() {
int n, k, a, b;
std::cin >> n >> k >> a >> b;
-- a, -- b;
std::vector<i64> x(n), y(n);
for (int i = 0; i < n; ++ i) {
std::cin >> x[i] >> y[i];
}
if (a > b) {
std::swap(a, b);
}
if (a < k && b < k) {
std::cout << 0 << "\n";
} else {
i64 mina = 1e18, minb = 1e18;
for (int i = 0; i < k; ++ i) {
mina = std::min(mina, std::abs(x[i] - x[a]) + std::abs(y[i] - y[a]));
minb = std::min(minb, std::abs(x[i] - x[b]) + std::abs(y[i] - y[b]));
}
if (a < k) {
mina = 0;
}
i64 ans = std::min(mina + minb, std::abs(x[a] - x[b]) + std::abs(y[a] - y[b]));
std::cout << ans << "\n";
}
}
C. Fill in the Matrix
题意:构造一个\(n\times m\)的数组,使得每一行都是\([0, n - 1]\)的排列,然后\(v_j\)代表第\(j\)列的\(mex\),总价值就是所有\(v_j\)的\(mex\)。求一个方案使得最终\(mex\)最大。
赛时手玩了一下就懂了。
0 1 2 3 4 5
5 0 1 2 3 4
4 5 0 1 2 3
3 4 5 0 1 2
2 3 4 5 0 1
0 1 2 3 4 5
就是从\((i, i)\)开始放\(0\)循环到\((i, i-1)\)依次放数。放到\(m-1\)行就行了,发现前\(m-1\)行就凑出了\(mex\)最大。剩下的行跟第一行一样就行了。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector a(n, std::vector<int>(m));
for (int i = 0; i < n; ++ i) {
if (i >= m - 1) {
for (int j = 0; j < m; ++ j) {
a[i][j] = j;
}
continue;
}
int x = 0;
for (int j = i; j < m; ++ j) {
a[i][j] = x ++ ;
}
for (int j = 0; j < i; ++ j) {
a[i][j] = x ++ ;
}
}
int ans = 0;
std::set<int> row;
for (int j = 0; j < m; ++ j) {
std::set<int> col;
int mex = 0;
for (int i = 0; i < n; ++ i) {
col.insert(a[i][j]);
while (col.count(mex)) {
++ mex;
}
}
// std::cout << mex << "\n";
row.insert(mex);
while (row.count(ans)) {
++ ans;
}
}
std::cout << ans << "\n";
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
std::cout << a[i][j] << " \n"[j == m - 1];
}
}
}
D1. Candy Party (Easy Version)
题意:\(n\)个人每个人有一个糖果。每个人必须恰好给一个人\(2\)的幂的糖果,并且恰好被一个人给糖果。要使得最终每个人的糖果数相等。
每个人要给出的糖果和接受的糖果数是固定的,记录下来看给出的和收入的\(2\)的幂的数量是不是一样。注意特判有一个人不过怎么凑的凑不出平均数的情况。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 sum = std::accumulate(a.begin(), a.end(), 0ll);
if (sum % n) {
std::cout << "NO\n";
return;
}
i64 x = sum / n;
std::vector<int> cnt1(30), cnt2(30);
for (int i = 0; i < n; ++ i) {
if (a[i] == x) {
continue;
}
bool flag = false;
for (i64 j = 0; j < 30; ++ j) {
for (i64 k = 0; k < 30; ++ k) {
if (a[i] + (1ll << j) - (1ll << k) == x) {
++ cnt1[j];
++ cnt2[k];
flag = true;
}
}
}
if (!flag) {
std::cout << "NO\n";
return;
}
}
for (int i = 0; i < 30; ++ i) {
if (cnt1[i] != cnt2[i]) {
std::cout << "NO\n";
return;
}
}
std::cout << "YES\n";
}
D2. Candy Party (Hard Version)
题意:跟\(D1\)一样,不过每个人可以选择给或不给。
发现如果这个人只给或者只接受,那么它和平均数的差是\(2\)的幂。例如\(a_i > x\),则可以表示为\(+2^i, - 0\),或者\(+2^{i+1}, -2^i\)。我们需要考虑应该选择哪一种。
发现这个只和两位有关,那么我们从高往低考虑,如果当前位的给出和收入不为0,就可以把\(+2^i, -0\)的变成\(+2^{i+1}, -2^i\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 sum = std::accumulate(a.begin(), a.end(), 0ll);
if (sum % n) {
std::cout << "NO\n";
return;
}
i64 x = sum / n;
std::vector<int> cnt1(30), cnt2(30);
std::vector<int> sum1(30), sum2(30);
for (int i = 0; i < n; ++ i) {
if (a[i] == x) {
continue;
}
bool flag = false;
for (i64 j = 0; j < 30; ++ j) {
if (a[i] - (1ll << j) == x) {
++ sum1[j];
flag = true;
break;
}
}
for (i64 j = 0; j < 30; ++ j) {
if (a[i] + (1ll << j) == x) {
++ sum2[j];
flag = true;
break;
}
}
if (flag) {
continue;
}
flag = false;
for (i64 j = 0; j < 30; ++ j) {
for (i64 k = 0; k < 30; ++ k) {
if (a[i] + (1ll << j) - (1ll << k) == x) {
++ cnt1[k];
++ cnt2[j];
flag = true;
}
}
}
if (!flag) {
std::cout << "NO\n";
return;
}
}
for (int i = 29; i ; -- i) {
int d = (cnt1[i] - cnt2[i] + sum1[i] - sum2[i]);
if (d > 0) {
if (sum2[i - 1] < d) {
std::cout << "NO\n";
return;
}
sum2[i - 1] -= d;
cnt1[i - 1] += d;
} else if (d < 0) {
d = -d;
if (sum1[i - 1] < d) {
std::cout << "NO\n";
return;
}
sum1[i - 1] -= d;
cnt2[i - 1] += d;
}
}
if (cnt1[0] - cnt2[0] + sum1[0] - sum2[0] != 0) {
std::cout << "NO\n";
return;
}
std::cout << "YES\n";
}

浙公网安备 33010602011771号