输入样例1:
5 2333
666 666 666 666 666
输出样例1:
0.0000
输入样例2:
10 30
2 1 4 7 4 8 3 6 4 7
输出样例2:
0.7928
解题思路:
要想使得标准差最小,即方差最小,应使得所有人的付账波动不能太大,理想状况是每人应该出正好平均值的钱,这样方差就是0。但是,当有人不够平均值时,就需要将他所有的钱都结付,尽可能的接近平均值,那这个人不够的部分就需要其他人来补上了,为了使每人出的钱都接近平均值,所以补的这部分需要“有能力担负的起的人”共同均摊。
支付时,应该先考虑钱拿的最少的,这样就算不够了后面也有人补贴,所以就需要给数组排序。当遍历到某个人时,如果发现钱不够平均值,就需要重新计算加上补贴这个人的平均值;如果发现他的钱已经不少于所需支付的平均值了,说明他之后的人钱数都已经足够了,为了确保精度,此时剩下人的平均值可以直接算出来,就不再需要再重复计算了。
Java代码:
import java.io.*;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] split = br.readLine().split(" ");
int n = Integer.parseInt(split[0]);
double s = Double.parseDouble(split[1]);
int []arr = new int[n];
split = br.readLine().split(" ");
for(int i = 0; i < n; i++)
arr[i] = Integer.parseInt(split[i]);
Arrays.sort(arr);
double avg = s / n; // 理论上每人应付的钱
double res = 0; // 方差
boolean flag = false; // 标志到某以个人时,是否之后的都足够结账
for(int i = 0; i < n; i++) {
double x = s / (n - i); // 当前平均值
if(arr[i] >= x) flag = true;
if(arr[i] < x) x = arr[i]; // 不够时,尽可能“多凑”
s -= x; // 剩下的人还需要结账的总数
if(!flag) res += (x - avg) * (x - avg); // 累加方差
else {
res += (x - avg) * (x - avg) * (n - i);
break;
}
}
System.out.printf("%.4f", Math.sqrt(res / n));
}
}