蓝桥杯-2018年A组-付账问题
0.题目
题目描述
几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。
现在有
为了公平起见,我们希望在总付钱量恰好为
标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。形式化地说,设第
输入格式
第一行包含两个整数
第二行包含
输出格式
输出到标准输出。
输出最小的标准差,四舍五入保留
保证正确答案在加上或减去
样例 #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
提示
【样例解释】
- 每个人都出 2333/5 元,标准差为 0。
【数据约定】
对于
对于
对于
对于
对于所有数据,
1.题解
1.1 贪心
思路
这里由于付钱总款固定, 人数固定, 所以平均值是固定的
总体思路使用到贪心的思想, 在尽可能使得每一步中每个人付的钱在后续足够的情况下,尽可能的少.
前面的不够(小于第一次计算的avg)后面的补上, 但当后面人总钱数大于(avg)的时候,我们就要考虑补多少
我们就可以考虑 还需要补的总钱数 / 剩余人数 = cur_avg(此种情况标准差最小);
可以这么思考, 我们在付完所有钱少于avg的人后, 如果我们希望剩余所有钱大于avg的人标准差最小, 有公式:
当所有
首先, 我们可以发现(
推导: 设常数
我们知道(
还知道(
而又有:
由于后面二者均为定值,所以总体就是前面的
总结:
若是当前人所持钱少于cur_avg, 那么就进一步计算新的cur_avg, 直到当前人钱大于当前cur_avg, 后面所有人均付cur_avg即可
我们可以简单分析一下,若能让每个人在够付账的情况下付的金额尽可能集中就可以使得标准差最小。
举个例子假如n = 10 , S = 30,每个人金额分别为1 , 2 , 3 , 4 , 4 , 4 , 6 , 7 , 7 , 8
先求出均值avg = 4.6,再对金额进行排序。
1.当金额小于均值时需要付出所有的钱;
2.当金额大于或等于均值时,这个人以及之后的所有人都需要在第一步完成的基础上重新计算均值即为cur_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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了