AtCoder Beginner Contest 203(Sponsored by Panasonic)
比赛链接:https://atcoder.jp/contests/abc203/tasks
A - Chinchirorin
题意
给出三个数,如果有两个数相同,输出剩下的那个数。
题解
模拟。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int a, b, c;
cin >> a >> b >> c;
if (a == b or b == c or a == c) {
cout << (a ^ b ^ c) << "\n";
} else {
cout << 0 << "\n";
}
return 0;
}
B - AtCoder Condominium
题意
一栋公寓有 \(n\) 层,每层有 \(k\) 个房间,第 \(i\) 层第 \(j\) 间房间号为 \(i0j\) ,计算所有房间号之和。
题解
模拟。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
ans += i * 100 + j;
}
}
cout << ans << "\n";
return 0;
}
C - Friends and Travel costs
题意
有无穷多个村庄,开始时 Taro 在村庄 \(0\) ,他可以花费 \(1\) 元从村庄 \(i\) 移动到村庄 \(i + 1\) 。
Taro 有 \(n\) 个朋友,给出他们所在的村庄 \(a_i\) 和 Taro 到达他们村庄时他们给 Taro 的钱数 \(b_i\) ,计算 Taro 最远可以到达的村庄。
题解
模拟。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n, k;
cin >> n >> k;
vector<pair<long long, int>> v(n);
for (int i = 0; i < n; i++) {
cin >> v[i].first >> v[i].second;
}
sort(v.begin(), v.end());
for (auto [x, y] : v) {
if (k >= x) {
k += y;
} else {
break;
}
}
cout << k << "\n";
return 0;
}
D - Pond
题意
给出一个 \(n\) 阶方阵,计算所有 \(k\) 阶方阵的中位数的最小值。
这里 \(k\) 阶方阵的中位数为: \(k^2\) 个数中第 \(\lfloor \frac{k^2}{2} \rfloor + 1\) 个大的数。
题解
二分中位数的值,将大于二分值的数记为 \(1\) ,小于等于的记为 \(0\) ,作二维前缀和来枚举所有 \(k\) 阶方阵。
如果存在一个方阵满足其和小于等于 \(\lfloor \frac{k^2}{2} \rfloor\) ,则当前二分值可行,设为上界,否则设为下界。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<vector<int>> a(n + 1, vector<int> (n + 1));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
int l = 0, r = 1e9, ans = 0;
while (l <= r) {
int mid = (l + r) / 2;
vector<vector<int>> pref_sum(n + 1, vector<int> (n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
pref_sum[i][j] = pref_sum[i - 1][j] + pref_sum[i][j - 1] - pref_sum[i - 1][j - 1] + (a[i - 1][j - 1] > mid);
}
}
bool possible = false;
for (int i = k; i <= n; i++) {
for (int j = k; j <= n; j++) {
if (pref_sum[i][j] - pref_sum[i - k][j] - pref_sum[i][j - k] + pref_sum[i - k][j - k] <= k * k / 2) {
possible = true;
}
}
}
if (possible) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans << "\n";
return 0;
}
E - White Pawn
题意
给出 \((2n + 1) \times (2n + 1)\) 的棋盘上 \(m\) 枚黑子的坐标,开始时一枚白子在 \((0, n)\) 处,白子的移动策略如下:
- 若 \((i + 1, j)\) 没有黑子,则可以移动到 \((i + 1, j)\)
- 若 \((i + 1, j - 1)\) 有黑子,则可以移动到 \((i + 1, j - 1)\)
- 若 \((i + 1, j + 1)\) 有黑子,则可以移动到 \((i + 1, j + 1)\)
问白子可能到达第 \(2n\) 行的哪些坐标。
题解
如果遇到空行白子只能往下移,即空行不影响纵坐标的变化。
所以从上往下依次枚举有黑子的行即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
map<int, vector<int>> mp;
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
mp[x].push_back(y);
}
set<int> prev_row{n};
for (auto [x, vec_y] : mp) {
vector<int> next_row;
for (auto y : vec_y) {
for (auto d : {-1, 1}) {
if (prev_row.count(y + d)) {
next_row.push_back(y);
}
}
}
for (auto y : vec_y) {
prev_row.erase(y);
}
for (auto y : next_row) {
prev_row.insert(y);
}
}
cout << prev_row.size() << "\n";
return 0;
}
F - Weed
题意
花园里有 \(n\) 株野草,Takahashi 和 Aoki 打算按如下方案拔掉这些野草:
- Aoki 先拔掉最多 \(k\) 株野草
- 之后 Takahashi 重复如下操作:
- 假设 \(h\) 为余下野草中的最大高度,拔掉所有高度大于 \(\lfloor \frac{h}{2} \rfloor\) 的野草
问在 Takahashi 操作最少次的情况下, Aoki 最少要拔掉多少株野草。
题解
设 \(dp_{ij}\) 为前 \(i\) 株野草 Takahashi 操作 \(j\) 次时 Aoki 要拔掉多少株。
-
若第 \(i\) 株由 Aoki 拔掉,那么有状态转移方程:
- \(dp_{ij} = min(dp_{ij}, dp_{i - 1j} + 1)\)
-
若第 \(i\) 株由 Takahashi 拔掉,由于其操作的特殊性,假设此时还剩 \(x\) 株,那么有状态转移方程:
- \(dp_{ij+1} = min(dp_{ij+1}, dp_{xj})\) ,即 Aoki 无需再对 \([x + 1, i]\) 间的野草进行任何操作。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());
const int m = 32;
const int INF = n;
vector<vector<int>> dp(n + 1, vector<int> (m, INF));
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1);
}
int x = upper_bound(a.begin(), a.end(), a[i - 1] / 2) - a.begin();
for (int j = 0; j + 1 < m; j++) {
dp[i][j + 1] = min(dp[i][j + 1], dp[x][j]);
}
}
for (int i = 0; i < m; i++) {
if (dp[n][i] > k) {
continue;
}
cout << i << ' ' << dp[n][i] << "\n";
break;
}
return 0;
}