洛谷P8664 [蓝桥杯 2018 省 A] 付账问题

原题链接—P8664 [蓝桥杯 2018 省 A] 付账问题

本题思路很简单 ,主打一个贪心

s=\sqrt{\frac{1}{n}\sum_{i=1}^{n}\left ( b_{i}-\frac{1}{n} \sum_{i=1}^{n} b_{i}\right )^{2}}

注意看这个公式(题面少了一个平方),\frac{1}{n}\sum_{i=1}^{n}b_{i}不就是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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一片在学code的小枫叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值