题解:P15574 [USACO26FEB] Milk Buckets S
_Kevin_Huang · · 题解
看了官方题解,感觉题解没有很好的解释每一步是什么来的,也可能是我太菜了,所以我来写一篇详细推导的题解。
设一个桶的容量为
第一个桶:每秒接受
一轮的时间是
第二个桶每次接受
以此类推。
第
它需要等待的次数是
所以第
第
以此类推,到了最后一个桶(第
所以第
为了计算池子中的牛奶数,我们应该计算在总时间
我们需要找到满足条件的最大翻转次数
移项:
如果
每次,第
最终池子有
但是直接 for 肯定会 TLE,不 TLE 也会爆 long long,因为一轮的时间
我们观察
回到题目,题目给定的
那一轮的时间最多翻转
所以,从上往下的推导中,真正会让某一个桶的翻转时间变大的,即
对于
我们可以使用 std::set 维护
对于每一次查询,我们只需要遍历 set 即可。
代码:
#include <iostream>
#include <set>
#include <vector>
int main() {
int n;
std::cin >> n;
std::vector<long long> a(n + 2, 0);
for (int i = 1; i <= n; i++) { std::cin >> a[i]; }
std::set<long long> s;
for (int i = 2; i <= n; i++) {
if (a[i] > a[i - 1]) s.insert(i);
else s.erase(i);
}
int q;
std::cin >> q;
while (q--) {
int i;
long long v, t;
std::cin >> i >> v >> t;
a[i] = v;
if (i >= 2) {
if (a[i] > a[i - 1]) s.insert(i);
else s.erase(i);
}
if (i + 1 >= 2 && i + 1 <= n) {
if (a[i + 1] > a[i]) s.insert(i + 1);
else s.erase(i + 1);
}
long long ans = std::max(0ll, t - (n - 1));
ans /= a[1] + 1;
for (int i : s) {
if (ans == 0) break;
long long r = (a[i] + a[i - 1] - 1) / a[i - 1];
ans /= r;
}
ans *= a[n];
std::cout << ans << std::endl;
}
}