赌注

题目大意:这 N 个分身每个都是庄家。你可以到庄家那边下注,每次可以猜大猜小,猜一次一元钱。每一次开彩前,你都可以到任意个庄家那里下赌注。如果开彩结果是大,你就可以得到你之前猜大的庄家相应的 ai元钱。如果开彩结果是小,你就可以得到你之前猜小的庄家相应的 bi元钱。你可以在同一个庄家那里既猜大又猜小(这样是两块钱),也可以什么都不猜(这样不用钱)。想要从它的分身中坑走尽量多的钱。但是会根据你下注的信息控制开彩的结果,让你赢的钱数尽量少。问怎么样下注,才能坑走神仙 czk 最多的钱

这题不难,是个贪心,可是考试时候怎么没有想到呢

题目转化:给定a,b两个序列,每次从a中选定一些数字,b中选定一些数字,其和分别即为 \(sum_a,sum_b\)

\[ans=\dfrac {min(sum_a,sum_b)}{(num_a+num_b)}\]

首先我们给他排个序,一定不会更差

考虑当我们取sumb为答案的时候,也就是suma一定比sumb大的时候的情况,维护双指针,挨个就可以了

然后再考虑取suma为答案的时候,也就是sumb一定比suma大的时候的情况

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 66;

double a[N], b[N], res;

inline bool cmp(double x , double y){return x > y;}

signed main()
{
int i, n = read();
for (i = 1; i <= n; ++ i) scanf ("%lf%lf", &a[i], &b[i]);

sort(a + 1, a + 1 + n, cmp), sort(b + 1, b + 1 + n, cmp);

double suma(0), sumb(0); int tot(1), num(0);
for (i = 1; i <= n; ++ i)
{
suma += a[i]; ++ num;

while (sumb + b[tot] <= suma && tot <= n)
{
sumb += b[tot ++]; ++ num;
res = max(res, sumb - num);
}

if (tot > n) break;
res = max(res, sumb - num);
}

suma = sumb = 0; tot = 1, num = 0;
for (i = 1; i <= n; ++ i)
{
sumb += b[i]; ++ num;

while (suma + a[tot] <= sumb && tot <= n)
{
suma += a[tot ++]; ++ num;
res = max(res, suma - num);
}

if (tot > n) break;
res = max(res, suma - num);
}

printf ("%.4lf", res);
return 0;
}