E. Gosha is hunting (dp + wqs套wqs)

本文探讨了神奇宝贝捕猎游戏中,如何通过优化算法来最大化预期捕获的神奇宝贝数量。通过对状态进行优化,利用WQS二分法,将复杂度从O(n^3)降至O(n^2logn),并通过进一步优化省略了b维度,实现了更高效的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E. Gosha is hunting
time limit per test
5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Gosha is hunting. His goal is to catch as many Pokemons as possible. Gosha has a Poke Balls and b Ultra Balls. There are nPokemons. They are numbered 1 through n. Gosha knows that if he throws a Poke Ball at the i-th Pokemon he catches it with probability pi. If he throws an Ultra Ball at the i-th Pokemon he catches it with probability ui. He can throw at most one Ball of each type at any Pokemon.

The hunting proceeds as follows: at first, Gosha chooses no more than a Pokemons at which he will throw Poke Balls and no more than b Pokemons at which he will throw Ultra Balls. After that, he throws the chosen Balls at the chosen Pokemons. If he throws both Ultra Ball and Poke Ball at some Pokemon, he is caught if and only if he is caught by any of these Balls. The outcome of a throw doesn't depend on the other throws.

Gosha would like to know what is the expected number of the Pokemons he catches if he acts in an optimal way. In other words, he would like to know the maximum possible expected number of Pokemons can catch.

Input

The first line contains three integers na and b (2 ≤ n ≤ 2000, 0 ≤ a, b ≤ n) — the number of Pokemons, the number of Poke Balls and the number of Ultra Balls.

The second line contains n real values p1, p2, ..., pn (0 ≤ pi ≤ 1), where pi is the probability of catching the i-th Pokemon if Gosha throws a Poke Ball to it.

The third line contains n real values u1, u2, ..., un (0 ≤ ui ≤ 1), where ui is the probability of catching the i-th Pokemon if Gosha throws an Ultra Ball to it.

All the probabilities are given with exactly three digits after the decimal separator.

Output

Print the maximum possible expected number of Pokemons Gosha can catch. The answer is considered correct if it's absolute or relative error doesn't exceed 10 - 4.

Examples
input
Copy
3 2 2
1.000 0.000 0.500
0.000 1.000 0.500
output
Copy
2.75
input
Copy
4 1 3
0.100 0.500 0.500 0.600
0.100 0.500 0.900 0.400
output
Copy
2.16
input
Copy
3 2 0
0.412 0.198 0.599
0.612 0.987 0.443
output
Copy
1.011


SOLUTION:

首先要优化状态,因为它本身三维状态。

我们试着不考虑a的限制,设状态dp_{i,j}dpi,j表示前i个神奇宝贝,使用j个超级球和若干精灵球的最大期望。

但是这样可能会多用一些精灵球。于是我们假设每次使用一个精灵球,需要花费一个代价caca,并在dp时记录精灵球的用量,设为uaua。那么实际期望就是dp_{i,b}+ua_n\times cadpi,b+uan×ca。

那么如何使它刚好使用a个精灵球呢?

发现精灵球用量随ca的增加而不增(不一定降)。

没错,二分ca。

于是,复杂度从O(n^3)O(n3)下降为O(n^2logn)O(n2logn),已经可以过了。

这就是wqs二分,二分一个附加费用使某一物品的使用量发生变化。

但是还可以优化。

既然a这一维可以被省略,b这一维为什么不可以呢?

于是我们用同样的方法设dp_idpi为前i只神奇宝贝,使用若干精灵球和超级球的期望,二分使用超级球的代价cbcb并记录dp过程中超级球的使用量ubub。

那么,实际代价就是dp_n+ua_n\times ca+ub_n\times cbdpn+uan×ca+ubn×cb

 

 

CODE:


#include <cstdio>
#include <cstring>
#include <algorithm>
#define T 60
#define N 2010
using namespace std;
typedef double LD;
const LD INF = 1e5;

LD u[N], v[N], q[N], L, R;
int n, a, b;

struct Node{
    LD val;
    int a, b;
    Node(LD V = 0, int A = 0, int B = 0) {
        val = V; a = A; b = B;
    }
    inline bool operator < (const Node &o) const {
        return val < o.val;
    }
    inline Node operator + (const Node &o) const {
        return Node(val + o.val, a + o.a, b + o.b);
    }
}dp[N];

inline void check_agn(LD x, LD y) {
    dp[0] = Node();
    for (int i = 1; i <= n; ++i) {
        dp[i] = Node(-INF, 0, 0);
        dp[i] = max(max(dp[i - 1], dp[i - 1] + Node(q[i] - x - y, 1, 1)), max(dp[i - 1] + Node(u[i] - x, 1, 0), dp[i - 1] + Node(v[i] - y, 0, 1)));
    }
}

inline void check(LD v) {
    L = 0, R = 1;
    for (int i = 1; i <= T; ++i) {
        LD mid = (L + R) / 2;
        check_agn(v, mid);
        if (dp[n].b >= b) L = mid;
        else R = mid;
    }
    check_agn(v, L);
}

int main() {
    scanf("%d%d%d", &n, &a, &b);
    for (int i = 1; i <= n; ++i) {
        scanf("%lf", &u[i]);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%lf", &v[i]);
    }
    for (int i = 1; i <= n; ++i) {
        q[i] = u[i] + v[i] - u[i] * v[i];
    }
    LD l = -1000, r = 1000;
    for (int i = 1; i <= T; ++i) {
        LD mid = (l + r) / 2;
        check(mid);
        if (dp[n].a >= a) l = mid;
        else r = mid;
    }
    check(l);
//  printf("%.5Lf %.5Lf\n %d %d \n", l, L, dp[n].a, dp[n].b);
    printf("%.5lf\n", dp[n].val + l * a + L * b);
    return 0;
}

  





转载于:https://www.cnblogs.com/zhangbuang/p/11242443.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值