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;
}
posted @ 2025-06-01 01:15  maburb  阅读(791)  评论(0)    收藏  举报