本文主要是介绍AcWing 1235. 付账问题(贪心),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
[题目概述]
几个人一起出去吃饭是常有的事。
但在结帐的时候,常常会出现一些争执。
现在有 n 个人出去吃饭,他们总共消费了 S 元。
其中第 i 个人带了 a i a_i ai 元。
幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?
为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。
这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。
你需要输出最小的标准差是多少。
标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。
形式化地说,设第 i 个人付的钱为 b i b_i bi
元,那么标准差为 :
输入格式
第一行包含两个整数 n、S;
第二行包含 n 个非负整数 a1, …, an。
输出格式
输出最小的标准差,四舍五入保留 4 位小数。
数据范围
1 ≤ n ≤ 5 × 1 0 5 1 ≤ n ≤ 5×10^5 1≤n≤5×105,
0 ≤ a i ≤ 1 0 9 0 ≤ a_i ≤ 10^9 0≤ai≤109,
0 ≤ S ≤ 1 0 1 5 0 ≤ S ≤ 10^15 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
现在感觉这贪心就是纯数学题 这题用到了均值不等式。
让我们求每个人付的钱数的标准差的最小值,也就是方差开根号,方差代表波动程度,那就是每个人付的钱最少最好,每个人都付账单的均值,这个想法的前提是你手里的前比均值大。要是手里的钱还不够付,那就有多少付多少,少付的在让其他人去均摊,这就是我们的第一步,猜想策略。(想不出来就嘎了)
接下来就是证明了
- a[i] >= s/n -> b[i] = s/n
- a[i] < s/n -> b[i] = a[i]
这样最难的这步证明也结束了,现在就根据这哥 贪心策略写代码就行。
- 完整代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>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 ++) cin >> a[i];// 必须要先排一次序,确保前面已经考虑的数有效sort(a, a + n);// long double是为了精度问题 long double sum = 0, avg = s / n;for(int i = 0; i < n; i ++){// cru是b[i],如果a[i] < cru,他就是账单的平均值double cru = s / (n - i);if(a[i] < cru) cru = a[i];sum += (cru - avg) * (cru - avg);s -= cru;}printf("%.4llf", sqrt(sum / n));return 0;
}
- 本题的分享就结束了,还是比较难得,尤其是想策略的第一步,有问题的小伙伴可以留言。
这篇关于AcWing 1235. 付账问题(贪心)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!