思路:
按钱数多少排序,从小往大考虑
每个人应该付多少钱。每个人理应付当前均摊费用,使得标准差最小
,若当前考虑的人钱不够付,则能付多少尽量付多少,使得后面的人尽可能少补
(1)若ai⩾
(2)若a_i<\dfrac{s_{剩余}}{n_{剩余}},付款a_i
原理:
1.当\sum\limits^n_{i=1}x_i=C(定值)时:
\sqrt{\dfrac{\sum\limits^n_{i=1}x^2_i}{n}}\geqslant\dfrac{\sum\limits^n_{i=1}x_i}{n},(几何平均数\geqslant算术平均数)
当且仅当x_i=\dfrac{C}{n}时取等
\therefore求标准差公式中的分子和最小值时,把(b_i-\dfrac{S}{n})当作x_i,
使用均摊法可以保证标准差最小
2.a+b=m(定值)时,2(a^2+b^2)-m^2=(a-b)^2
\therefore和一定的两个数,他们相差得越小,则他们的平方之和越大
故若当前考虑的这位同学没有足够的钱,应当付完自己所有的钱,
减少他和其他同学付款的差,保证标准差最小
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 500010;
int n;
int a[N];
int main()
{
long double s;
cin >> n >> s;
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
sort(a, a + n);
long double res = 0, avg = s / n;
for (int i = 0; i < n; i ++ )
{
// 当前均摊费用
double cur = s / (n - i);
if (a[i] < cur) cur = a[i]; // 不够付时 能付多少付多少
res += (cur - avg) * (cur - avg); // 方差分子累加
s -= cur; // 剩余未付总费用(供剩下的人均摊)
}
printf("%.4Lf\n", sqrt(res / n));
return 0;
}