洛谷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;
}

### 蓝桥杯竞赛题目的多种解法与思路分析 #### 付账问题(贪心算法) 对于 AcWing 1235. 付账问题,该题目属于典型的贪心算法应用实例。此问题的核心在于通过合理分配金额来最小化最大支付额。具体实现上,先计算平均值并以此为基础调整每个人的付款数额,从而达到整体最优效果[^1]。 ```python def min_max_payment(payments, average): surplus = sum([max(0, p - average) for p in payments]) deficit = sum([min(0, p - average) for p in payments]) return max(abs(surplus), abs(deficit)) ``` #### N皇后问题(回溯 vs 动态规划) 关于经典的N皇后放置难题,在处理较大规模输入时单纯依靠暴力枚举效率低下。采用回溯方法能够有效减少不必要的尝试次数;而当棋盘尺寸固定且较小的情况下,则可考虑利用动态规划求得全局最优解路径[^2]。 ```cpp bool solveNQ(int col[], int row){ if (row >= n) { printSolution(col); return true; } bool res = false; for (int i=0; i<n && !res; ++i){ if (isSafe(i, row, col)){ col[row]=i; res = solveNQ(col, row+1) || res; col[row]=-1; } } return res; } ``` #### 差分数组的应用场景 差分技术主要用于解决区间修改操作频繁的数据结构设计挑战。通过对原始序列构建对应的增量表,可以在O(1)时间复杂度内完成单点更新以及查询任意子区间的累加和运算[^3]。 ```java public class DifferenceArray { private final int[] diff; public DifferenceArray(int[] nums) { assert nums.length > 0; this.diff = new int[nums.length]; // 构造差分类 diff[0] = nums[0]; for (int i = 1; i < nums.length; i++) { diff[i] = nums[i] - nums[i - 1]; } } /* 给闭区间 [left,right] 增加 val */ public void increment(int left, int right, int val) { diff[left] += val; if (right + 1 < diff.length) { diff[right + 1] -= val; } } /* 返回结果数组 */ public int[] result() { int[] res = new int[diff.length]; // 根据差分数组构造结果数组 res[0] = diff[0]; for (int i = 1; i < diff.length; i++) { res[i] = res[i - 1] + diff[i]; } return res; } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一片在学code的小枫叶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值