CF436E Cardboard Box

题意:有两个数组a和b,你可以花费ai代价买1个球,也可以花费bi代价买两个,也可以不买,每个i只能有一个操作。问买到恰好k个球的最小代价。

我目前见过的最复杂的反悔贪心。
我们贪心的想每次一个一个球的加,那么我们有四种加法:

  1. 从没有用过的i里用ai代价买一个球。
  2. 从用ai的i里选择用bi买两个球,之前买的那个球退还,代价是 bi - ai
  3. 从没有用过的i里选bi买两个球,然后从之前用aj的j里退还一个球,代价是 bi - aj
  4. 从没有用过的i里选bi买两个球,然后之前用bj的j里退还一个球,变成用aj买一个球,代价是 bi - (bj - aj)

那么我们用set维护最小的没买过球位置的ai, 最小的买一个球位置的bi - ai,最大的买过一个球位置的ai,最大的买过两个球位置的bi - ai, 最小的没买过球位置的bi。 那么第一二个操作好说,第三个操作就是最小的没买过球位置的bi - 最大的买过一个球位置的ai, 第四个操作就是最小的没买过球位置的bi - 最大的买过两个球位置的bi - ai
注意每次操作对四个set的影响。

点击查看代码
void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<i64> a(n), b(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i] >> b[i];
	}


	using PII = std::pair<i64, int>;
	std::set<PII, std::greater<PII> > s3, s4;
	std::set<PII> s1, s2, s5;
	for (int i = 0; i < n; ++ i) {
		s1.insert({a[i], i});
		s5.insert({b[i], i});
	}

	std::string ans(n, '0');
	i64 sum = 0;
	while (k -- ) {
		i64 min = 1e18, op = 0;
		if (s1.size() && s1.begin()->first < min) {
			min = s1.begin()->first;
			op = 1;
		} 

		if (s2.size() && s2.begin()->first < min) {
			min = s2.begin()->first;
			op = 2;
		}

		if (s5.size() && s3.size() && s5.begin()->first - s3.begin()->first < min) {
			min = s5.begin()->first - s3.begin()->first;
			op = 3;
		}

		if (s5.size() && s4.size() && s5.begin()->first - s4.begin()->first < min) {
			min = s5.begin()->first - s4.begin()->first;
			op = 4;
		}

		sum += min;
		if (op == 1) {
			int i = s1.begin()->second;
			s1.erase({a[i], i});
			s2.insert({b[i] - a[i], i});
			s3.insert({a[i], i});
			s4.erase({b[i] - a[i], i});
			s5.erase({b[i], i});
			ans[i] = '1';
		} else if (op == 2) {
			int i = s2.begin()->second;
			s1.erase({a[i], i});
			s2.erase({b[i] - a[i], i});
			s3.erase({a[i], i});
			s4.insert({b[i] - a[i], i});
			s5.erase({b[i], i});
			ans[i] = '2';
		} else if (op == 3) {
			int i = s5.begin()->second, j = s3.begin()->second;
			s1.erase({a[i], i});
			s2.erase({b[i] - a[i], i});
			s3.erase({a[i], i});
			s4.insert({b[i] - a[i], i});
			s5.erase({b[i], i});

			s1.insert({a[j], j});
			s2.erase({b[j] - a[j], j});
			s3.erase({a[j], j});
			s4.erase({b[j] - a[j], j});
			s5.insert({b[j], j});

			ans[i] = '2';
			ans[j] = '0';
		} else if (op == 4) {
			int i = s5.begin()->second, j = s4.begin()->second;
			s1.erase({a[i], i});
			s2.erase({b[i] - a[i], i});
			s3.erase({a[i], i});
			s4.insert({b[i] - a[i], i});
			s5.erase({b[i], i});

			s1.erase({a[j], j});
			s2.insert({b[j] - a[j], j});
			s3.insert({a[j], j});
			s4.erase({b[j] - a[j], j});
			s5.erase({b[j], j});

			ans[i] = '2';
			ans[j] = '1';
		}
	}
	std::cout << sum << "\n";
	std::cout << ans << "\n";
}
posted @   maburb  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示