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;
}
posted @ 2022-09-20 09:54  zuytong  阅读(22)  评论(0编辑  收藏  举报