ACdream ~ 1066 ~ Bet(数学 or 二分+精度)

思路:因为我们要使最坏的情况获得钱最多,肯定要让不管哪一个赢都能得到一样的钱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;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值