Codeforces Round 1057 (Div. 2) A~D

A. Circle of Apple Trees

模拟。

可以一直循环,那么将原数组去重排序后,第 \(i\) 轮吃第 \(i\) 个就可以把所有不同的数字都吃掉,即答案就是去重后的元素个数。

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

using namespace std;

using i64 = long long;

void solve() {

	int n;
	std::cin >> n;

	int ans = 0;
	std::vector<int> b(n + 1);
	for (int i = 0; i < n; i += 1) {
		int x;
		std::cin >> x;
		ans += b[x] == 0;
		b[x] += 1;
	}

	std::cout << ans << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

B - Bitwise Reversion

思维,位运算。

\(a\& b = X,\ b\& c = Y\),那么有 \((a\& b)\& (b\&c)=X\&Y=a\&b\&c\),同理可得 \((a\& b)\& (b\&c)=(a\& b)\& (a\&c)=(a\& c)\& (b\&c)\),即满足 \(a\&b=a\&c=b\&c\) 即可。

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

using namespace std;

using i64 = long long;

void solve() {

	int x, y, z;
	std::cin >> x >> y >> z;

	std::cout << ((x & y) == (y & z) && (x & z) == (x & y) ? "YES\n" : "NO\n");
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

C - Symmetrical Polygons

分类讨论。

满足多边形的条件之一是任意边都需要小于其他边之和。

要形成对称轴,显然偶数条边都是可以选的,记偶数条边的和为 \(sum\),对对称轴穿过几条边分类讨论:

  • 穿过两个顶点,即穿过零条边:此时答案等于 \(sum\),但前提偶数条边大于 \(2\)
  • 穿过一条边:枚举奇数边 \(x\),取最大满足 \(x<sum\)\(x+sum\)
  • 穿过两条边:枚举奇数边 \(x\),找最大满足 \(y<x+sum\)\(y\),且 \(x<y+sum\),此时取最大的 \(x + y + sum\)
点击查看代码
#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n;
	std::cin >> n;

	std::map<int, int> mp;
	std::vector<int> a(n);
	for (int i = 0; i < n; i += 1) {
		std::cin >> a[i];
		mp[a[i]] += 1;
	}

	i64 res = 0;
	int use = 0, used = 0;
	std::set<i64> has;
	for (auto &[x, y] : mp) {
		int k = y - (y % 2);
		res += 1LL * x * k;
		use += k;
		if (y & 1) {
			has.insert(x);
		}
	}

	i64 ans = use > 2 ? res : 0;

	for (auto &x : has) {
		if (x < res) {
			ans = max(ans, res + x);
		}
	}

	std::vector<int> vec(has.begin(), has.end());
	for (auto x : vec) {
		has.erase(x);
		auto t = has.lower_bound(x + res);
		if (t != has.begin() &&  x < res + *prev(t)) {
			t = prev(t);
			ans = max(ans, res + x + *t);
		}
		has.insert(x);
	}

	std::cout << ans << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

D - Not Alone

\(dp\)

这个漂亮数组可以分成若干个长度为 \(2\)\(3\) 的值相同的子数组。

\(dp_i\) 表示将前 \(i\) 个数分成两种长度的子数组的最小代价,代价即是子数组的极值差,记为 \(cost\);那么有转移 \(dp_i=\min(dp_{i-2}+cost_{a_i,a_{i-1}},dp_{i-3}+cost_{a_i,a_{i-1},a_{i-2}})\)

因为可以为环形,那么最多左移三次进行 \(dp\) 求最小值即可。

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

using i64 = long long;

void solve() {

	int n;
	std::cin >> n;

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

	const i64 inf = 1E15;

	auto cost = [](int x,int y)->int{
		return abs(x - y);
	};
	auto cost2 = [](int x,int y,int z)->int{
		return std::max({x, y, z}) - std::min({x, y, z});
	};

	i64 ans = inf;
	for(int x = 0; x < 3; x += 1) {
		std::vector<i64> dp(n + 1, inf);
		for(int i = 1; i < n; i += 1) {
			dp[i] = std::min(dp[i], (i - 2 >= 0 ? dp[i - 2] : 0) + cost(a[i], a[i - 1]));
			if(i >= 2){
				dp[i] = std::min(dp[i], (i - 3 >= 0 ? dp[i - 3] : 0) + cost2(a[i], a[i - 1], a[i - 2]));
			}
		}
		ans = std::min(ans, dp[n - 1]);
		std::rotate(a.begin(), a.begin() + 1, a.end());
	}

	std::cout << ans << "\n";

}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int t;
	std::cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}
posted @ 2025-10-15 19:34  Ke_scholar  阅读(17)  评论(0)    收藏  举报