第九屆藍橋杯省賽C++A組 付賬問題(貪心)
阿新 • • 發佈:2021-01-11
幾個人一起出去吃飯是常有的事。
但在結帳的時候,常常會出現一些爭執。
現在有 n 個人出去吃飯,他們總共消費了 S 元。
其中第 i 個人帶了 ai 元。
幸運的是,所有人帶的錢的總數是足夠付賬的,但現在問題來了:每個人分別要出多少錢呢?
為了公平起見,我們希望在總付錢量恰好為 S 的前提下,最後每個人付的錢的標準差最小。
這裡我們約定,每個人支付的錢數可以是任意非負實數,即可以不是 1 分錢的整數倍。
你需要輸出最小的標準差是多少。
標準差的介紹:標準差是多個數與它們平均數差值的平方平均數,一般用於刻畫這些數之間的“偏差有多大”。
形式化地說,設第 i個人付的錢為 bi 元,那麼標準差為 :
輸入格式
第一行包含兩個整數 n、S;
第二行包含 n 個非負整數 a1, …, an。
輸出格式
輸出最小的標準差,四捨五入保留 4 位小數。
資料範圍
1≤n≤5×105
0≤ai,S≤109
輸入樣例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
首先我們要知道標準差表示的是資料的波動程度,其值越大波動越大。 要使得標準差小,我們就要儘可能使得資料都比較接近平均值。那麼 這題貪心策略應該是這樣的:首先算出平均值s/ns/n,把資料從小到 大排序,如果某個人的錢低於該值,那麼他一定是將錢全部支付,然 後其餘不夠的其他人平攤。但是,由於之前那個人錢不夠,那麼就會 導致剩下人支付的平均值會增大,所以在這個平攤過程中很有可能存 在某個人錢又低於這個平均值,又需要剩下的人平攤。如此反覆,直到支付完成。
#include<bits/stdc++.h>
using namespace std;
int n,s;
int a[500010];
int main(){
cin>>n>>s;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
double res=s*1.0/n;
double k=res;
int ans;
for(int i=0;i<n;i++){
if(a[i]< res){
s-=a[i];
res=s*1.0/(n-1-i);//要乘1.0
}
else{
ans=i;
break;
}
}
double t=0;
for(int i=0;i<ans;i++){
t+=(a[i]-k)*(a[i]-k);
}
for(int i=ans;i<n;i++){
t+=(res-k)*(res-k);
}
printf("%.4lf",sqrt(t/n));
return 0;
}