CF505E Mr. Kitayuta vs. Bamboos
最小化最大值就是二分答案,我们现在二分最后最大值为 \(H\),希望知道能否让最终的值都不超过 \(H\)。
发现正着做很不可做,考虑时光倒流:
一开始所有的竹子都是 \(H\) 这么高,每天会自己降低 \(a_i\),然后我们有权用 \(k\) 次“拔高”的机会,每次可以拔高 \(p\)。要求:每时每刻都不能存在一个竹子的高度为负数(不可能有从负数长出来的情况);最终每个竹子的高度都 \(\ge h_i\)(真实情况下如果低一些顶多就是某一天砍到 0 就不砍到负数了,但是如果高一些的话最终就达不到 \(H\) 了)
这两个要求中,第一个要求最为紧急,必须在“死期”之前赶紧拔高;第二个要求就什么时候拔都行了,随便找一个拔即可。由于如果现在啥也不拔就能够保证符合第二个要求的话,第一个要求就肯定不成问题了,或者说在不拔的情况下不符合第一个要求就一定不符合第二个要求,因此我们可以直接拔最快到“死期”的那个竹子,这是最优决策。
相关参数:死期 \(= \left \lfloor \frac{H}{a_i} \right \rfloor + 1\)
关键代码:
inline bool che(ll H) {
while (!q.empty()) q.pop();
for (int i = 1; i <= n; ++i) nw[i] = H;
for (int i = 1; i <= n; ++i)
if (H - 1ll * m * a[i] < h[i]) q.push(MP(-(H/a[i]),i));
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= k; ++j) {
if (q.empty()) return true;
PLL pr = q.top(); q.pop();
if (-pr.first < i) return false;
int id = pr.second;
nw[id] += p;
if (nw[id] - 1ll * m * a[id] < h[id]) q.push(MP(-(nw[id]/a[id]),id));
}
}
return q.empty();
}