Loading

Codeforces Round #763 (Div. 2) C - Balanced Stone Heaps

题意:
给定\(n\)堆石子,然后第\(i\)堆石子的数量为\(h_i\),现在从第\(3\)堆石子到第\(n\)堆石子依次的进行如下操作:选择一个整数\(d(0\le3\times d\le h_i)\),分配给第\(i - 1\)\(d\)个石子,分配给第\(i - 2\)\(d\times2\)个石子,问最后这堆石子中的最小值最大可以为多少?

  • 一眼二分
  • 注意题目中需要按照从前往后的顺序搬运石子,这就意味着后面补充的石子不能再用来补充前面的空,也就是某个位置能搬向前面位置的石子最多就是\(h_i\)
  • 注意到这点后,我们直接从后往前贪心的让每个位置恰好\(\ge\)二分枚举的值即可,有上述第二点保证了从后向前的合法性
  • \(O(nlogn)\)
#include <bits/stdc++.h>

using namespace std;

//特殊在 题目要求操作的顺序是从前往后 但是我们从后面转移计算
//此时 需要注意 当前石子后面转移过来的石子不能再用了 因为从前往后注定了后面的石子只能往前搬一次

void solve() {
	int n,limit = 0; cin >> n;
	vector<int>h(n + 1);
	for(int i = 1;i <= n;i ++) {
		cin >> h[i];
		limit = max(limit,h[i]);
	}
	auto check = [&](int x) {
		vector<int>T(n + 1);
		for(int i = 1;i <= n;i ++) T[i] = h[i];
		for(int i = n;i >= 3;i --) {
			if(T[i] < x) return false;
			int d = min(T[i] - x,h[i]) / 3;
			//T[i]此时代表的是后面的石子能补充过来的最大值 它可以帮助我们达到合法答案 但是不能用于向前搬运 所以要加个min
			T[i - 1] += d;
			T[i - 2] += d * 2;
		}
		if(T[1] < x || T[2] < x) return false;
		return true;
	};
	int l = 1,r = limit,ans;
	while(l <= r) {
		int mid = l + r >> 1;
		if(check(mid)) {
			// cout << l << ' ' << r << ' ' << mid << '\n';
			ans = mid,l = mid + 1;
		} else {
		 	r = mid - 1;
		}
	}
	cout << ans << '\n';
}

int main() {
	int T; cin >> T;
	while(T --) {
		solve();
	}
	return 0;
}
posted @ 2022-05-11 20:14  x7x7g7c7  阅读(375)  评论(0)    收藏  举报