第九届蓝桥杯省赛 C++ A组 - 付账问题

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    ✍个人博客https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
    📚专栏地址蓝桥杯题解集合
    📝原题地址付账问题
    📣专栏定位为想考甲级PAT的小伙伴整理常考算法题解祝大家都能取得满分
    ❤️如果有收获的话欢迎点赞👍收藏📁您的支持就是我创作的最大动力💪

    问题描述

    几个人一起出去吃饭是常有的事。

    但在结帐的时候常常会出现一些争执。

    现在有 n 个人出去吃饭他们总共消费了 S 元。

    其中第 i 个人带了 ai 元。

    幸运的是所有人带的钱的总数是足够付账的但现在问题来了每个人分别要出多少钱呢

    为了公平起见我们希望在总付钱量恰好为 S 的前提下最后每个人付的钱的标准差最小。

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

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

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

    形式化地说设第 i 个人付的钱为 bi 元那么标准差为 :

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OHTOg5ng-1673831661293)(AcWing 蓝桥杯辅导.assets/19_6734517a16-p1.png)]

    输入格式

    第一行包含两个整数 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
    

    思路

    由题可知标准差的公式如下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BicCoebY-1673831661297)(AcWing 蓝桥杯辅导.assets/image-20221227144755868.png)]

    根据均值不等式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C15fBwtq-1673831661300)(AcWing 蓝桥杯辅导.assets/image-20221227144833252.png)]

    可知 x 1 + x 2 + . . . + x n x_1+x_2+...+x_n x1+x2+...+xn 等价于 ( b 1 − s / n ) 2 + ( b 2 − s / n ) 2 + . . . + ( b n − s / n ) 2 (b_1-s/n)^2+(b_2-s/n)^2+...+(b_n-s/n)^2 (b1s/n)2+(b2s/n)2+...+(bns/n)2 又因为 b 1 + b 2 + . . . + b n = s b_1+b_2+...+b_n=s b1+b2+...+bn=s s / n ∗ n = s s/n*n=s s/nn=s b 1 − s / n + b 2 − s / n + . . . + b n − s / n = s − s = 0 b_1-s/n+b_2-s/n+...+b_n-s/n=s-s=0 b1s/n+b2s/n+...+bns/n=ss=0

    所以我们可以得出如下结论

    1. a i > = s / n a_i>=s/n ai>=s/n 时取平均数这里可由上面等式推出。
    2. a i < s / n a_i<s/n ai<s/n b i = a i b_i=a_i bi=ai b i < a i b_i<a_i bi<ai这里可由两个值的均值不等式推出证明略。

    总的来说就是如果带的钱够交总花费的平均数就至少交这个平均数如果不够则有多少出多少然后将平均数与其差值分摊到其他人身上即让别人帮你垫。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 500010;
    int a[N];
    int 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++)
        {
            long 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;
    }
    
  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: c++