欢迎来到下蛋爷之家|

下蛋爷

园龄:4年2个月粉丝:8关注:23

CF626G Raffles 题解

Description

  • n 个奖池,第 i 个奖池的奖金是 pi,已经有 li 张彩票押在上面。
  • 现在你有 t 张彩票,你需要将你的彩票分配到这些奖池中,并且保证你在每个奖池中押的彩票数不能超过该奖池原有的彩票数
  • 若你在第 i 个奖池中押了 ti 张彩票,则你中奖的概率为 titi+li,若你中奖,你可以获得这个奖池的全部奖金 pi
  • 一共有 q 次事件,每次事件会使某个 li1 或减 1
  • 你需要在每个事件后求出在最佳方案下你获得的奖金总数的最大期望值。
  • n,t,q2×105pi,li103,答案精度误差 106

Solution

首先单次 O(tlogn) 是很容易的,就先假设所有 ti=0,每次取出让 titi+1 的增量的最大值,由于对于每个 iti 越大增量越小,所以每次贪心取最大值是对的。

考虑怎么支持修改。

不妨设修改了 x,让 lxlx+1

有一个结论是每次选出当前已经选择的 Δ 里的最小值和没选的 Δ 的最大值,如果这个最小值小于最大值就贪心地替换,替换的次数不超过 1 次。

证明就考虑设 ΔE(k)=pxlx(lx+k)(lx+k+1),ΔE(k)=px(lx+1)(lx+k+1)(lx+k+2)

注意到 ΔE(k)=px(lx+1)(lx+k+1)(lx+k+2)>ΔE(k+1)=pxlx(lx+k+1)(lx+k+2),所以 x 只有可能是选了的最小的增量被替换,所以最多只有一次。

对于 lxlx1 的情况同理可证结论仍成立。

时间复杂度:O((n+q+t)logn)

Code

#include <bits/stdc++.h>
// #define int int64_t
using f64 = long double;
const int kMaxN = 2e5 + 5;
int n, m, q;
f64 ans;
int l[kMaxN], p[kMaxN], t[kMaxN];
std::multiset<std::pair<f64, int>> st[2];
f64 getdet(int x, int v) {
return (f64)p[x] * l[x] / (l[x] + t[x]) / (l[x] + t[x] + v);
}
void add(int x) {
--m;
st[1].erase({getdet(x, 1), x});
if (t[x]) st[0].erase({getdet(x, -1), x});
ans += getdet(x, 1), ++t[x];
st[0].emplace(getdet(x, -1), x);
if (t[x] < l[x]) st[1].emplace(getdet(x, 1), x);
}
void del(int x) {
++m;
if (t[x] < l[x]) st[1].erase({getdet(x, 1), x});
st[0].erase({getdet(x, -1), x});
ans -= getdet(x, -1), --t[x];
if (t[x]) st[0].emplace(getdet(x, -1), x);
st[1].emplace(getdet(x, 1), x);
}
void dickdreamer() {
std::cin >> n >> m >> q;
for (int i = 1; i <= n; ++i) std::cin >> p[i];
for (int i = 1; i <= n; ++i) std::cin >> l[i];
for (int i = 1; i <= n; ++i) st[1].emplace(getdet(i, 1), i);
for (; m && !st[1].empty();) add(st[1].rbegin()->second);
for (int i = 1; i <= q; ++i) {
int op, x;
std::cin >> op >> x;
if (op == 1) {
if (t[x]) st[0].erase({getdet(x, -1), x});
if (t[x] < l[x]) st[1].erase({getdet(x, 1), x});
ans -= (f64)p[x] * t[x] / (t[x] + l[x]);
++l[x];
} else {
if (t[x] == l[x]) del(x);
if (t[x]) st[0].erase({getdet(x, -1), x});
if (t[x] < l[x]) st[1].erase({getdet(x, 1), x});
ans -= (f64)p[x] * t[x] / (t[x] + l[x]);
--l[x];
}
ans += (f64)p[x] * t[x] / (t[x] + l[x]);
if (t[x]) st[0].emplace(getdet(x, -1), x);
if (t[x] < l[x]) st[1].emplace(getdet(x, 1), x);
for (; m && !st[1].empty();) add(st[1].rbegin()->second);
if (!st[0].empty() && !st[1].empty()) {
auto [det1, j1] = *st[0].begin();
auto [det2, j2] = *st[1].rbegin();
if (det1 < det2) del(j1), add(j2);
}
std::cout << std::fixed << std::setprecision(10) << ans << '\n';
}
}
int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}
posted @   下蛋爷  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起