CF1623C Balanced Stone Heaps
CF1623C
原题链接←Click it
题目大意:有\(i(i >= 3)\)堆石子,每堆石子的个数为\(h_i\),现在从第\(3\)堆到第\(n\)堆石子进行操作,每次都可以选择\(d\)个石头,使得\(h_{i - 2} += 2 * d\),\(h_{i_1} += d\),\(h_i -= 3 * d\)。求操作完成之后数量最少的堆中石子可能的最大值。
解题思路:显然是一个二分查找,但是check函数在写的过程中有些波折。刚开始的时候我是选择从顺序模拟,但是发现对第\(i\)堆石子操作的时候,发现如果第\(i - 2\)堆石子满足条件,但是第\(i - 1\)堆石子不满足条件的情况下,我们就必须要考虑第\(i + 1\)堆石子对\(i - 1\)堆的贡献。也就是说从顺序模拟需要考虑之后的不确定因素,但是逆序模拟的时候,可以贪心地让第\(i\)堆石子剩下可能的最小值,因为前面的堆无法影响到后面的堆,因此理论上我们对第\(i\)堆石子每次可移动的\(d =\lfloor \frac{nh[i] - m}{3} \rfloor\),但是实际上在顺序模拟的过程中发现每堆石子可移动的\(d <= \lfloor \frac{h[i]}{3}\rfloor\),因此我们可以贪心地取\(d = min(\lfloor \frac{nh[i] - m}{3} \rfloor,\lfloor \frac{h[i]}{3}\rfloor)\),并检查每个\(nh[i]\)是否大于\(m\)。
参考代码:
vector<int> h;
bool check(int m) {
vector<int> nh = h;
for(int i = nh.size() - 1; i >= 2; i --) {
if(nh[i] < m) return 0;
int d = min(h[i], nh[i] - m) / 3;
nh[i - 1] += d;
nh[i - 2] += 2 * d;
}
return b[0] >= m && b[1] >= m;
}
void solve() {
int n;
cin >> n;
a.resize(n);
int l = INF, r = INF;
for(int i = 0; i < n;i ++) {
cin >> a[i];
l = min(l, a[i]);
}
while(l < r) {
int m = l + r + 1 >> 1;
if(check(m)) l = m;
else r = m - 1;
}
cout << l << '\n';
}