Codeforces Round 1028 (Div. 2)
A. Gellyfish and Tricolor Pansy
题意:两个人分别有\(a, b\)滴血。两个人的武器有\(c, d\)血。攻击必须用武器,可以攻击对方和对方武器。两个人轮流攻击,第一个人先。求谁赢。
如果第一个想赢,那么要么一直打对面本身,要么把对面武器打没。
点击查看代码
void solve() {
int a, b, c, d;
std::cin >> a >> b >> c >> d;
if ((c >= d && a > d - 1) || (a >= b && c >= b)) {
std::cout << "Gellyfish\n";
} else {
std::cout << "Flower\n";
}
}
B. Gellyfish and Baby's Breath
题意:给你两个\(0\)到\(n-1\)的排列\(a, b\),\(r_i = \max_{j=0}^{i} 2^{a_j} + 2^{b_{i-j}}\)。求\(r\)。
\(a, b\)应该至少选一个最大的。那么记录前缀最大的数的位置,得到两种情况,比较谁更大。
代码省略取模类。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n), b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
int pa = 0, pb = 0;
for (int i = 0; i < n; ++ i) {
if (a[i] > a[pa]) {
pa = i;
}
if (b[i] > b[pb]) {
pb = i;
}
std::pair<int, int> x = {a[pa], b[i - pa]}, y = {b[pb], a[i - pb]};
if (x < y) {
x = y;
}
std::cout << power<Z>(2, x.first) + power<Z>(2, x.second) << " \n"[i == n - 1];
}
}
C. Gellyfish and Flaming Peony
题意:给你一个数组,每次选两个数,使得其中数变成它们的\(gcd\)。求所有数变成一样的最小操作数。
显然最后变成的数是整个数组的\(gcd\)。那么应该选最少的数使得可以得到数组的\(gcd\),那么其它数和这个数操作就一步到位了。问题变为选择最少的数使得它们的\(gcd\)等于数组的\(gcd\)。观察到\(a_i \leq 5000\)。可以\(f[i][j]\)表示前\(i\)个\(gcd\)为\(j\)最少选几个数。使用滚动数组优化一下内存可以通过。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int d = 0;
for (auto & x : a) {
d = std::gcd(x, d);
}
if (*std::min_element(a.begin(), a.end()) == d) {
std::cout << n - std::ranges::count(a, d) << "\n";
return;
}
const int inf = 1e9, N = 5000;
std::vector f(N + 1, inf);
f[0] = 0;
for (int i = 0; i < n; ++ i) {
for (int j = 1; j <= N; ++ j) {
f[std::gcd(a[i], j)] = std::min(f[std::gcd(a[i], j)], f[j] + 1);
}
f[a[i]] = 1;
}
std::cout << f[d] - 1 + n - 1 << "\n";
}
D. Gellyfish and Camellia Japonica
题意:有一个数组\(a\),和\(q\)个操作\((x_i, y_i, z_i)\),每次使得\(a_{z_i} = \min(a_{x_i}, z_{y_i})\)。操作完成后\(a\)变成了\(b\)。现在给出\(b\)和所有操作,求一个合法的\(a\)。
考虑反着来。显然有\(a_{x_i}= \max(a_{x_i}, a_{z_i}), a_{y_i}= \max(a_{y_i}, a_{z_i})\)。然后从头模拟一遍看能不能变成\(b\)。这样能过样例,但会\(wa3\)。原因是可能前面还有\(a_{z_i}\)的操作,且此时\(a_{z_i} = \min(a_{x_j}, a_{y_j})\)是比\(\min(a_{x_i}, z_{y_i})\)要小的,而我们没有更改\(a_{z_i}\)的值。那么可以使得\(a_{z_i} = 0\),这样\(a_{x_j}, a_{y_j}\)就能得到一个正确的下界。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
std::vector<std::tuple<int, int, int>> op(q);
for (int i = 0; i < q; ++ i) {
int x, y, z;
std::cin >> x >> y >> z;
-- x, -- y, -- z;
op[i] = {x, y, z};
}
std::ranges::reverse(op);
auto a = b;
for (auto & [x, y, z] : op) {
a[x] = std::max(a[x], a[z]);
a[y] = std::max(a[y], a[z]);
if (x != z && y != z) {
a[z] = 0;
}
}
auto c = a;
std::ranges::reverse(op);
for (auto & [x, y, z] : op) {
c[z] = std::min(c[x], c[y]);
}
if (b == c) {
for (int i = 0; i < n; ++ i) {
std::cout << a[i] << " \n"[i == n - 1];
}
} else {
std::cout << -1 << "\n";
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}