2023 CCPC Final G

G. China Convex Polygon Contest

反悔贪心。

首先可以考虑对 \(b\) 排序,显然思考越快的题可以使手里攒着的题更多更有选择的空间。

如果正着贪心的话就是,当前能做就立马提交,如果当前的时间更优但选不了就从之前丢一个小的然后选择当前;但是会存在这样一个情况,刚开始把 \(a_x-a_k\) 丢进堆,然后到了 \(b_y\),如果 \(a_y-b_y \ge a_z-a_y\),自然选当前段更好,但是反之 \(a_z-a_y>a_y-a_x>a_x-a_k\),我们就要抛弃掉之前的 \(a_x-a_k\),让 \(b_x\) 去选 \(a_y-a_x\) 段,\(b_y\) 去选 \(a_z-a_y\)

因为你不知道 \(b_y\) 是否会在后面更优,于是对于 \(b_y-a_x\) 这一段你就得考虑怎样去维护,由于你的堆里维护的是你选了的,所以你不能直接丢进去,发现这个东西不好维护。
image

正难则反,考虑反着遍历。

维护一个最大堆,维护你没有选过的答案,枚举到当前 \(a_i\) 时,假设这一段区间内有 \(x\)\(b_j\),除去最后一个需要特殊处理一下,那么前 \(x-1\) 个显然是选择堆顶的 \(x-1\) 个贡献,这些答案显然是确定的且更优,最后可能会剩一些没用完的 \(b\),但是后面已经没有贡献了,我们只考虑最接近 \(a_i\) 的那个 \(b\),以 \(a_x\)\(b_y\) 为例,如果目前堆中仍有答案且比 \(a_y-b_y\) 更优,那么显然,我们这个 \(b_y\) 选后面的更优,这一段直接就放 \(a_y-a_x\) 进去让更前面的选;否则就选上当前的 \(a_y-b_y\),然后把 \(b_y-a_x\) 加到堆顶(记为 \(S\rightarrow S+b_y-a_x\) ),如果你后续有 \(b\) 选到了这个堆顶,意味着,是之前那个 \(b\) 反悔了选了 \(S\),而现在这个 \(b\) 选了 \(a_y-a_x\),但是总的贡献仍然有 \(S + a_y - a_x\)

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

using i64 = long long;

void solve() {

	int n, m;
	std::cin >> n >> m;

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

	sort(b.begin(), b.end());
	for(int i = 1; i < n; i += 1) {
		b[i] += b[i - 1];
	}

	while(b.size() && b.back() > m) {
		b.pop_back();
	}

	int ans = 0;

	std::priority_queue<int> pq;
	for(int i = n; i >= 0; i -= 1) {
		std::vector<int> vec;
		while(b.size() && b.back() >= a[i]) {
			vec.push_back(b.back());
			b.pop_back();
		}

		std::reverse(vec.begin(), vec.end());
		while(vec.size() > 1 && pq.size()) {
			ans += pq.top();
			pq.pop();
			vec.pop_back();
		}

		if(vec.size()) {
			int x = a[i + 1] - vec[0];
			int y = 0;
			if(pq.size()) {
				y = pq.top();
				pq.pop();
			}

			if(y >= x) {
				ans += y;
				pq.push(a[i + 1] - a[i]);
			} else {
				ans += x;
				y += vec[0] - a[i];
				pq.push(y);
			}
		} else {
			pq.push(a[i + 1] - a[i]);
		}
	}

	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-11 12:31  Ke_scholar  阅读(18)  评论(0)    收藏  举报