原题链接—P8664 [蓝桥杯 2018 省 A] 付账问题
本题思路很简单 ,主打一个贪心。
注意看这个公式(题面少了一个平方),不就是S/n嘛!也就是平均数。
所以我们只需要每个人付的钱数尽可能接近平均数就是最优解(贪啊贪啊贪)。
如果拥有的钱数不够平均数则全付掉,用dum记录付掉的钱与平均数的差值和(这需要带更多钱的人来付);把拥有钱数大于平均数的人放进小根堆q(也可以使用数组),将堆里面的人拥有的钱数与平均值的差和差值平均数(p)作比较,如果某个人够支付这个差值则后续的人都可以支付的起;如果某个人支付不起这个差值那么就能付多少付多少,更新差值平均数,再往下比较即可。最后不要忘了结果保留4位小数。(ps:一定要使用long long和long double。别问为什么,说多了都是泪QAQ)
最后附上ac代码:
#include <bits/stdc++.h>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q;//建一个小根堆
int main(void)
{
int n, a;
long long S;
long double sum{}, dum{};//sum记录每个人付的钱数与平均数的差值平方和,dum记录所带钱数不够平均数的人钱数与平均值差值总和
cin >> n >> S;
double x = S * 1.0 / n; // x代表平均数
for (int i = 0; i < n; i++)
{
cin >> a;
if (a > x)//如果拥有的钱数比平均数大,入队
{
q.push(a);
}
if (a < x)//如果拥有的钱数比平均数小,则全付掉
{
sum += pow(a - x, 2);
dum += x - a;
}
}
if (q.size())
{
while (!q.empty())
{
double p = dum / q.size(); // 比平均数多的人该付的部分
if (q.top() - x >= p)//如果有一个人以及足够支付,则后续的人都可以支付的起
{
sum += q.size() * p * p;
break;
}
else//如果不够支付该部分,那能给多少给多少,更新差值平均数
{
sum += pow(q.top() - x, 2);
dum -= q.top() - x;
q.pop();
}
}
}
cout << fixed << setprecision(4) << sqrt(sum / n);
return 0;
}