蓝桥杯2018年A组-付账问题

0.题目

题目描述

几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。

现在有 n 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。形式化地说,设第 i 个人付的钱为 bi 元,那么标准差为 s=1ni=1n(bi1ni=1nbi)

输入格式

第一行包含两个整数 nS

第二行包含 n 个非负整数 a1,,an

输出格式

输出到标准输出。

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

保证正确答案在加上或减去 109 后不会导致四舍五入的结果发生变化。

样例 #1

样例输入 #1

5 2333
666 666 666 666 666

样例输出 #1

0.0000

样例 #2

样例输入 #2

10 30
2 1 4 7 4 8 3 6 4 7

样例输出 #2

0.7928

提示

【样例解释】

  1. 每个人都出 2333/5 元,标准差为 0。

【数据约定】

对于 10% 的数据,所有 ai 相等;

对于 30% 的数据,所有非 0ai 相等;

对于 60% 的数据,n1000

对于 80% 的数据,n105

对于所有数据,n5×105,0ai109

1.题解

1.1 贪心

思路

这里有很多需要注意的点:
1.这里我们首先明确一点:最终计算的avg是固定的,即 S / n
2.我们主要弄清一个问题:每个人付款有多有少,谁多谁少,如何让这个标准差最小
3.使用贪心的思路: 首先我们为了逼近avg:
3.0首先我们对于整个数组进行排序,便于后续使用贪心算法(这里sort排序,注意1.我a数组从下标1开始; 2.第二个参数是结束位置的下一个位置)
3.1如果存在有些钱不够的人(a[i] < avg),这些人两种选择:付全款/付部分; 如果他们付部分,他们自身首先和avg形成的标准差更大;其次对于后面有富裕的人,他们本来可
以用更接近avg的钱即可付完全款,但是由于你少付了,他们都要多付,跟avg的标准差也就更大;所以对于这部分人我们选择全部付款
3.2出现第二种人,有富裕,但不多(a[i] >= avg), 这些人能付的钱已经大于平均值,但是由于前面有人少付了钱,这时候我支付avg是不够的,需要他们进行多付.又回到了这
个问题,他们是全付还是付部分即可? 我们可以利用之前的遍历,更新剩余需支付的S,计算出新的平均值(总人数 n-i+1)avg', 对于剩余这部分的人,如果持钱最少的人都多
于avg',那么对于后面钱更多的人,也是能付起avg'的,而且这时候整体最逼近于avg(接近avg的都尽可能全付,直到出现一个符合的avg'),剩余部分的人只需要付avg'的钱款
即可.
4.这里判断 a[i] >= avg', 并不是写作 a[i] >= S' / (n - i + 1) 而是写作乘法,避免精度确实的问题!!!
5.注意最后所有人不是付款当前人持有的a[i], 而是均支付 avg' 即可, 由于持有钱款不是连续, 可能当前 a[i] > avg'!!!

代码

#include<bits/stdc++.h>
#define ll long long
const int M = 5e5 + 1;
ll a[M];
using namespace std;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	ll S;
	cin >> n >> S;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}

	sort(a+1, a+n+1);
	double avg = (S * 1.0) / n,  differ = 0;
	for(int i = 1; i <= n; i++) {
		// 钱够了,全部支付
		if (a[i] * (n - i + 1) >= S) {
			double remain_avg = S * 1.0 / (n-i+1);
			differ += (n - i + 1) * pow(remain_avg - avg, 2);
			break;
		} else {
			S -= a[i];
			differ += pow(a[i] - avg, 2);
		}
	}

	differ = sqrt(differ / n);
	printf("%.4lf", differ);
	return 0;
}
posted @   DawnTraveler  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示