Codeforces Round 1045 (Div. 2)


A. Painting With Two Colors

题意:一个长度为\(n\)的数组,先把一段长度为\(a\)的子数组染为红色,再把一段长度为\(b\)的子数组染为蓝色,蓝色会覆盖红色。求能不能使得数组是回文。

因为要左右对称,所以肯定是染色的两个子数组的中心位置应该相同。
那么如果\(a > b\)\(a\)\(n\)的奇偶性不同则无解,因为红色部分不能对称,而蓝色又无法覆盖红色。
如果\(a < b\)\(b\)\(n\)的奇偶性不同则无解,因为蓝色一定覆盖红色,此时只需关注蓝色能不能构成回文。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, a, b;
	std::cin >> n >> a >> b;
	if (b % 2 == n % 2 && (b > a || a % 2 == n % 2)) {
		std::cout << "YES\n";
	} else {
		std::cout << "NO\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;
}

B. Add 0 or K

题意:一个数组,每次让数组每个数要么加上\(0\)要么加上\(k\)。求能不能使得数组\(gcd > 1\)

简单做法是猜出\(gcd = k + 1\)。然后遍历一遍就行了。
我的写法是求一个不是\(k\)的因子的质数,设它为\(gcd\),那么有\(a_i + tk \equiv 0 \pmod p\)。那么有\(t \equiv -a_i \times k^{-1} \pmod p\)。因为\(p\)是质数,可以用费马小定理求\(k\)的逆元求出\(t\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

const int primes[] = {
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29
};

int power(int a, int b, int p) {
    int res = 1;
    for (;b;b >>= 1, a = (i64)a * a % p) {
        if (b & 1) {
            res = (i64)res * a % p;
        }
    }

    return res;
}

void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<i64> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

    int p = 0;
    for (auto & x : primes) {
        if (k % x) {
            p = x;
            break;
        }
    }

    int inv = power(k % p, p - 2, p);
    for (int i = 0; i < n; ++ i) {
        i64 x = a[i] % p;
        i64 b = (p - x) * inv % p;
        a[i] += b * k;
    }
    for (int i = 0; i < n; ++ i) {
        std::cout << a[i] << " \n"[i == n - 1];
    }
}

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;
}

C. Even Larger

题意:一个数组,每次操作使得一个数减一,不能小于\(0\)。求所有子数组的偶数位和大于等于奇数位和的最小操作。

发现只要\(a_i \geq a_{i-1} + a_{i+1}\)就行,其中\(i\)是偶数。
那么考虑怎么减,从左到右做,显然应该尽量减\(a_{i+1}\),因为它对后面有影响。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<i64> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	i64 ans = 0;
	for (int i = 1; i < n; i += 2) {
		i64 x = a[i - 1];
		if (i + 1 < n) {
			x += a[i + 1];
		} 
		i64 t = std::max(0ll, x - a[i]);
		ans += t;
		if (i + 1 < n) {
			i64 t1 = std::min(a[i + 1], t);
			a[i + 1] -= t1;
			t -= t1;
		}
	}
	std::cout << ans << "\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;
}

D. Sliding Tree

题意:一棵树,每次选择\(a, b, c\)满足\(b\)\(a, c\)都有边,然后把\(b\)\(a\)外的所有两边接到\(c\)上。需要把树变为链,求一个最小操作方案的第一次操作。

链的直径长度为\(n\),最小操作方案一定是每次让树的直径加一。
那么只需要找到一次让直径长度加一的操作。
考虑找出一条树的直径,然后枚举其中的点,找到一个度数大于等于\(3\)的点,拿它当\(b\),然后用直径上它左右两个点中距离端点最近的点当作\(a\),然后再选一个不在直径上的邻点作为\(c\)。那么直径长度就会加一。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<std::vector<int>> adj(n);
	for (int i = 1; i < n; ++ i) {
		int u, v;
		std::cin >> u >> v;
		-- u, -- v;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}

	int max = 0;
	for (int i = 0; i < n; ++ i) {
		max = std::max<int>(max, adj[i].size());
	}

	if (max <= 2) {
		std::cout << -1 << "\n";
		return;
	}

	auto bfs = [&](int s) -> int {
		std::vector<int> d(n, -1);
		std::queue<int> q;
		q.push(s);
		d[s] = 0;
		while (q.size()) {
			int u = q.front(); q.pop();
			for (auto & v : adj[u]) {
				if (d[v] == -1) {
					d[v] = d[u] + 1;
					q.push(v);
				}
			}
		}

		return std::max_element(d.begin(), d.end()) - d.begin();
	};

	int U = bfs(0);
	int V = bfs(U);

	std::vector<int> path;
	auto dfs = [&](auto & self, int u, int fa) -> bool {
		if (u == V) {
			path.push_back(u);
			return true;
		}

		for (auto & v : adj[u]) {
			if (v == fa) {
				continue;
			}

			if (self(self, v, u)) {
				path.push_back(u);
				return true;
			}
		}
		return false;
	};

	dfs(dfs, U, -1);
	int a = -1, b = -1, c = -1;
	for (int i = 0; i < path.size(); ++ i) {
		int u = path[i];
		if (adj[u].size() >= 3) {
			b = u;
			a = i < (int)path.size() - 1 - i ? path[i - 1] : path[i + 1];
			for (auto & v : adj[u]) {
				if (v != path[i - 1] && v != path[i + 1]) {
					c = v;
					break;
				}
			}
			break;
		}
	}

	std::cout << a + 1 << " " << b + 1 << " " << c + 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;
}

E. Power Boxes

题意:交互题。一个数组\(a\),每个元素为\(1\)\(2\)。记\(f[n + 1] = 0, f[i] = f[i + a_i] + 1\)。你每次可以询问\(i\)得到\(f_i\)的值,或者交换\(i\)\(i + 1\)\(f\)的值也会相应改变。求原数组每个元素的的值。最多操作\(\lceil \frac{3n}{2} \rceil\)次。

考虑先求得\(f\)数组,那么如果\(f_{i+1} \ne f_{i+2}\),则可以确定\(a_i\)的值,否则\(a_i\)的值暂时无法确定,因为\(f_{i+1} = f_{i+2}\),则不管\(a_i\)\(1\)还是\(2\)\(f_i\)都是一样的,那么没必要查询\(f_i\)的值。
然后结论是相邻两个数值一定有一个的\(a_i\)值是确定的。因为如果\(i\)不能确定,则有\(f_i \ne f_{i+1}\),那么\(i-1\)的值就能确定。
则最多有\(\lceil \frac{n}{2} \rceil\)个位置不能去掉,那么想要确定这些位置就必须用到交换操作了。
如果\(i\)不能确定,那么因为\(i+1\)是确定的,则有\(f_{i+2} \ne f_{i+3}\),考虑交换\(i, i+1\),则可以询问\(i+1\)得到\(a_{i}\)的值。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void swap(int x) {
	std::cout << "swap " << x << std::endl;
}

int Throw(int x) {
	std::cout << "throw " << x << std::endl;
	int res;
	std::cin >> res;
	return res;
}

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> ans(n + 1);
	std::vector<int> f(n + 2);
	f[n] = 1;
	for (int i = n - 1; i >= 1; -- i) {
		if (f[i + 1] == f[i + 2]) {
			f[i] = f[i + 1] + 1;
		} else {
			f[i] = Throw(i);
			ans[i] = f[i] == f[i + 1] + 1 ? 1 : 2;
		}
	}

	for (int i = 1; i < n; ++ i) {
		if (ans[i] == 0) {
			swap(i);
			f[i + 1] = Throw(i + 1);
			ans[i] = f[i + 1] == f[i + 2] + 1 ? 1 : 2;
		}
	}

	swap(n - 1);
	ans[n] = Throw(n - 1) == 1 ? 2 : 1;

	std::cout << "!";
	for (int i = 1; i <= n; ++ i) {
		std::cout << " " << ans[i];
	}
	std::cout << std::endl;
}

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-08-27 02:01  maburb  阅读(572)  评论(2)    收藏  举报