比赛链接: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) << "
";
} else {
cout << 0 << "
";
}
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 << "
";
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 << "
";
return 0;
}
D - Pond
题意
给出一个 (n) 阶方阵,计算所有 (k) 阶方阵的中位数的最小值。
这里 (k) 阶方阵的中位数为: (k^2) 个数中第 (lfloor frac{k^2}{2} floor + 1) 个大的数。
题解
二分中位数的值,将大于二分值的数记为 (1) ,小于等于的记为 (0) ,作二维前缀和来枚举所有 (k) 阶方阵。
如果存在一个方阵满足其和小于等于 (lfloor frac{k^2}{2} floor) ,则当前二分值可行,设为上界,否则设为下界。
代码
#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 << "
";
return 0;
}
E - White Pawn
题意
给出 ((2n + 1) imes (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() << "
";
return 0;
}
F - Weed
题意
花园里有 (n) 株野草,Takahashi 和 Aoki 打算按如下方案拔掉这些野草:
- Aoki 先拔掉最多 (k) 株野草
- 之后 Takahashi 重复如下操作:
- 假设 (h) 为余下野草中的最大高度,拔掉所有高度大于 (lfloor frac{h}{2} floor) 的野草
问在 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] << "
";
break;
}
return 0;
}