开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
题目链接
题目
题目大意
波波联队(BU)和波波城(BC)之间的足球比赛即将开始。你需要为每支球队设定赔率。
有 个人准备在下注,第 个人认为 BU 有 的概率获胜。
如果你为 BU 设置赔率为 ,为 BC 设置赔率为 ,那么第 个人:
- 如果 ,他将在 BU 上下注。
- 如果 ,他将在 BC 上下注。
令在 BU 上下注的总金额为 美元,在 BC 上下注的总额为 美元。如果 BU 最终赢得比赛,公司需要支付 美元;如果 BC 获胜,公司需要支付 美元。在最坏的情况下,利润是 。
合理设置 和 的值,以在最坏的情况下实现利润最大化,输出最大的收益。
思路
让我们对于人的行为模式进行化简,原题意可以转化为对于第 个人:
- 如果 ,他将在 BU 上下注。
- 如果 ,他将在 BC 上下注。
为了不让人在两边都下注,应该使 。
所以我们对所有人按 属性排序后,对任一种可能成为最优解的答案,存在下标 满足 且对于每一个人 :
- 若 ,他在 BC 上下注。
- 若 ,他不下注。
- 若 ,他在 BU 上下注。
显然 变大时 应该变小,双指针更新答案即可。
应对数据 值相等的位置去重或进行相应处理。
代码
#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
const int N=1000001;
const LL mod=1000000007;
//const LL mod=998244353;
struct asdf{
long double p;
LL c;
bool operator < (const asdf a) const
{
return p<a.p;
}
}a[N];
int n;
long double sum[N];
long double getans(int i,int j)
{
return sum[i]+sum[n]-sum[j-1]-max(sum[i]*(1.0/(1-a[i].p)),(sum[n]-sum[j-1])*(1.0/a[j].p));
}
LL solve()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%Lf%lld",&a[i].p,&a[i].c);
sort(a+1,a+1+n);
int tot=1;
for (int i=2;i<=n;++i)
if (a[i].p!=a[i-1].p) a[++tot]=a[i];
else a[tot].c+=a[i].c;
n=tot;
for (int i=1;i<=n;++i)
sum[i]=sum[i-1]+a[i].c;
sum[n+1]=sum[n];
long double ans=0,x;
for (int i=1,j=n;i<=n;++i)
{
x=getans(i,j);
while (i<j-1&&getans(i,j-1)>=x)
{
j--;
x=getans(i,j);
}
ans=max(ans,x);
}
printf("%.15Lf",ans);
}
int main()
{
int T=1;
while (T--) solve();
return 0;
}