此题来源自蓝桥杯。
问题描述:
几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。
现在有 nn 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?
为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。你需要输出最小的标准差是多少。
标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的"偏差有多大"。形式化地说,设第 i个人付的钱为 bi 元,那么标准差为 :
输入描述
输出描述
代码如下:
//贪心策略求解,先从小到大进行排序, 如果排序后第一个人的前数少于S/n,则为了减小标准差,此人应拿出所有的钱,
//如果第一个人的钱大于S/n,则后面所有人的钱数都大于S/n,此时每个人都出S/n即可。
//对于第二个人也是这样考虑,只是S和n的值可能会改变。
//后面所有的人都这样进行考虑。
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=5e5+10;
long long a[N]; //题目中虽然说到ai用int类型既能存储,但这里要定义为long long ,因为下面有语句a[i]*(n-i+1)>=S,该语句左边可能是long long
int main(){
int n;
long long S; //S可能为 long long 类型
cin>>n>>S;
double avg=S*1.0/n; //不要忘记乘以1.0
double r_avg;
double ans=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
if(a[i]*(n-i+1)>=S){
r_avg=S*1.0/(n-i+1);
ans+=(r_avg-avg)*(r_avg-avg)*(n-i+1);
break;
}
else{
S-=a[i];
ans+=(a[i]-avg)*(a[i]-avg);
}
}
printf("%.4lf",sqrt(ans*1.0/n));
return 0;
}