CF436E Cardboard Box

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

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

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

那么我们用set维护最小的没买过球位置的\(a_i\), 最小的买一个球位置的\(b_i\) - \(a_i\),最大的买过一个球位置的\(a_i\),最大的买过两个球位置的\(b_i\) - \(a_i\), 最小的没买过球位置的\(b_i\)。 那么第一二个操作好说,第三个操作就是最小的没买过球位置的\(b_i\) - 最大的买过一个球位置的\(a_i\), 第四个操作就是最小的没买过球位置的\(b_i\) - 最大的买过两个球位置的\(b_i\) - \(a_i\)
注意每次操作对四个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 @ 2025-01-14 14:56  maburb  阅读(17)  评论(0)    收藏  举报