付账问题(贪心思路看待均分,零基础都可以理解)

付账问题

文章目录

  • 付账问题
    • 前言
    • 问题描述
    • 问题分析
    • 代码

前言

上一次我们讲述了相邻的均分问题,这一次的均分问题没有距离限制,但是要求将标准差控制在最小值,也就是将整个函数的离散化控制在最小值,后续还会继续更新贪心有关的内容,感兴趣的小伙伴可以点个关注啦!
往期文章如下
雷达设备问题(从另一个角度看待区间合并 + 贪心思路 + 未发现关键的错误样例)
糖果传递问题(超详细的数论公式推导+贪心结论+均分问题)

问题描述

几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。
现在有 n 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai 元。
幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?
为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。

这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。

你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。

形式化地说,设第 i 个人付的钱为 bi 元,那么标准差为 :
付账问题(贪心思路看待均分,零基础都可以理解)_第1张图片

输入格式
第一行包含两个整数 n、S;
第二行包含 n 个非负整数 a1, …, an。

输出格式
输出最小的标准差,四舍五入保留 4 位小数。

数据范围
1≤n≤5×105,
0≤ai≤109,
0≤S≤1015。

输入样例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

问题分析

注意观察标准差的公式,我们要将有些数是常数,比如说∑bi,实际上就是总和s,同理,n也是知晓的。为了将标准差控制在最小值,我们要从离散化的角度入手。
对于那些带的钱高于平均值的人,我们要让他们出的钱尽可能贴近于平均值
对于那些带的钱低于平均值的老六,我们需要让他们交出全部的钱去贴近平均值

这里我们的平均值不是一成不变的,因为老六的缺钱,只能让钱多的大哥来垫底,
同时还要保障钱多的大哥出的钱贴合当前的平均值,因此,每次遍历一个老六,我们就要太高相应的平均值去让后面的大哥垫上钱【题目保证能够钱】

代码

详细的解析都在代码注释当中啦

#include
#include
#include
using namespace std;
const int N = 5e5 + 7;
int a[N];
long double s;
int n;
int main(){
    cin>>n>>s;
    for(int i=1;i<=n;i++) cin>>a[i];
    long double ave=s/n,cur_ave=ave,sum=0;
    //输入的数据和输出的数据要用long double来存储
    //不然数据过不了
    sort(a+1,a+1+n);//为什么要排序呢?
    //这里我们要将老六全部放在在前面,防止那些有钱的大哥出少了钱
    for(int i=1;i<=n;i++){
        if(a[i]<cur_ave){
            s-=a[i];
            sum+=(a[i]-ave)*(a[i]-ave);
            cur_ave=s/(n-i);//这里由于老六的缘故,要更新平均值
        }
        else{
            sum+=(cur_ave-ave)*(cur_ave-ave);
        }
        
    }
    printf("%.4Lf",sqrt(sum/n));
}

你可能感兴趣的:(贪心,算法入门,蓝桥杯,c++,贪心算法,均分问题)