【贪心】硬币游戏
题意
一共有\(n\)个庄家。
你可以到庄家那边下注,每次可以猜大猜小,猜一次需要一个单位的花费(可以都猜,也可以都不猜,都猜花费\(2\)个单位)。
可以到任意个庄家那里下赌注。
开彩结果不是大就是小。
如果开彩结果是大,你就可以得到你之前猜大的庄家相应的\(a_i\)单位的收益。
如果开彩结果是小,你就可以得到你之前猜小的庄家相应的\(b_i\)单位的收益。
请你设定一个策略,使得你在最坏情况下的收益最大。
思路
最坏情况即取开小和开大中结果的最小值。
可以发现,因为可以都下注,就可以把\(a\)和\(b\)分开做。
实际上求得就是这个东西:\(max(min(\sum_{i \in S_1}a_i,\sum_{i \in S_2}b_i)-(c(S_1)+c(S_2)))\)(即赌\(c(S_1)\)个小,\(c(S_2)\)个大)
固定\(c(S_1)+c(S_2)\),则求\(min(\sum_{i \in S_1}a_i,\sum_{i \in S_2}b_i)\)最大。
如果枚举\(c(S_1)和c(S_2)\),肯定取最大的\(c(S_1)和c(S_2)\)个\(a_i和b_i\)做比较,然而复杂度是\(O(n^2)\)的。
不妨令小的一边是\(a\),那么随着\(a\)增大,相应的\(b\)也应增大。用两个指针维护即可。对于小的一边为\(b\),也做一遍即可。此处也是取前若干个最大值,易证。
代码
#include <cstdio>
#include <algorithm>
int n;
double ans;
double a[100001], b[100001];
bool cmp(double x, double y) {
return x > y;
}
int main() {
freopen("coin.in", "r", stdin);
freopen("coin.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lf %lf", &a[i], &b[i]);
std::sort(a + 1, a + n + 1, cmp);
std::sort(b + 1, b + n + 1, cmp);
for (int i = 1; i <= n; i++) {
a[i] += a[i - 1];
b[i] += b[i - 1];
}
for (int i = 1, j = 1; i <= n && j <= n; i++) {
for (; a[i] - i - j > b[j] - i - j && j <= n; j++)
;
if (j <= n) ans = std::max(ans, a[i] - i - j);
}
for (int i = 1, j = 1; i <= n && j <= n; i++) {
for (; b[i] - i - j > a[j] - i - j && j <= n; j++)
;
if (j <= n) ans = std::max(ans, b[i] - i - j);
}
printf("%.4lf", ans);
}

浙公网安备 33010602011771号