思路:因为我们要使最坏的情况获得钱最多,肯定要让不管哪一个赢都能得到一样的钱V。在总钱数X一定的情况下,如果有某个赢之后获得的钱大于V,那么肯定有某个赢之后的钱少于V,如果是其他都输了而这个赢钱少的赢了那么得到的钱就比V少。题目中问的就是最坏情况下的最大收益(最大化平均值),所以我们应该让不管哪个赢获得钱都一样的钱V。那么怎么求V呢?有两种思路:
①我们可以二分这个数字,然后通过判断在回报都为V时的投入跟实际总钱数X的关系确定如何缩小区间。
②其实我们可以发现是有规律的,假设平均回报为v,每个赔率为a[i],总钱数为X,我们可以得到下面这个式子
化简得所以
X跟a[1~n]都已知,所以答案V可以求出来,然后保留个两位小数输出就可以了。
公式法:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
double a[105],x,v;
while(~scanf("%d",&n))
{
for(int i = 0; i < n; i++) scanf("%lf",&a[i]);
scanf("%lf",&x);
v = 0.0;
for(int i = 0; i < n; i++) v += 1 / a[i];
printf("%.2lf\n",x / v);
}
return 0;
}
二分法:
这个首先二分是一个有关精度的二分问题,所以结束条件为l-r<eps,每次缩区间也不能让L或R等于m±1了,而是等于M±eps。因为我们二分的是回报,所以最小回报L=0.00,最大回报等于总钱数乘赔率的最大值,即R = ,如果再去找太麻烦了,题意中说到了a的取值范围为[0.01,100],所以我们直接初始R=X*100就可以了。
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int n;
double a[105],x,v;
double check(double m)
{
double sum = 0.0;
for(int i = 0; i < n; i++)
{
sum += m / a[i];
}
return sum;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 0; i < n; i++) scanf("%lf",&a[i]);
scanf("%lf",&x);
double l = 0.0,r = x * 100,m = l + (r - l) / 2.0;
while(r - l > eps)
{
if(check(m) < x) l = m + eps;
else if(check(m) > x) r = m - eps;
else break;
m = l + (r - l) / 2.0;
}
printf("%.2lf\n",m);
}
return 0;
}