CF739E Gosha is hunting
思路
WQS 二分优化 DP 的经典例题
显然我们有 \(O(nab)\) 的 DP 做法,(不知道卡卡能不能过呢?)
我们考虑对 \(a\) 球做 WQS 二分
每次二分一个 \(mid\),对于所有与 \(a\) 有关期望都减去 \(mid\)(包括同时使用 \(a,b\) 球的情况)
而对于 \(b\) 球,我们每次排序后选择前 \(b\) 大的球即可
算出选择了多少个 \(a\) 球,与要求的比较
二分中排序的期望计算细节见代码
代码
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int rd()
{
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
int n, a, b; double pa[2005], pb[2005];
double pos, ans;
struct Node
{
double w; int v1, v2;
}s[2005];
inline int chk(double mid)
{
int cnt = 0; ans = 0;
FOR(i, 1, n)
{
if(pb[i] > pa[i] + pb[i] - pa[i] * pb[i] - mid) s[i].w = pb[i], s[i].v2 = 0;
else s[i].w = pa[i] + pb[i] - pa[i] * pb[i] - mid, s[i].v2 = 1;
if(pa[i] - mid > 0) s[i].v1 = 1, s[i].w -= pa[i] - mid, ans += pa[i] - mid;
else s[i].v1 = 0;
}
std::sort(s + 1, s + 1 + n, [&](Node a, Node b){return a.w > b.w;});
FOR(i, 1, n)
{
if(i <= b) ans += s[i].w, cnt += s[i].v2;
else cnt += s[i].v1;
}
return cnt;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
n = rd(), a = rd(), b = rd();
FOR(i, 1, n) scanf("%lf", pa + i);
FOR(i, 1, n) scanf("%lf", pb + i);
double l = 0, r = 1;
while(l + 1e-8 < r)
{
double mid = (l + r) / 2.0;
if(chk(mid) >= a) pos = mid, l = mid;
else r = mid;
}
chk(pos); printf("%.9lf", ans + a * pos);
return 0;
}