一、題目
幾個人一起出去喫飯是常有的事。但在結帳的時候,常常會出現一些爭執。
現在有 n 個人出去喫飯,他們總共消費了 S 元。其中第 i 個人帶了 ai 元。幸運的是,所有人帶的錢的總數是足夠付賬的,但現在問題來了:每個人分別要出多少錢呢?
爲了公平起見,我們希望在總付錢量恰好爲 S 的前提下,最後每個人付的錢的標準差最小。這裏我們約定,每個人支付的錢數可以是任意非負實數,即可以不是1分錢的整數倍。你需要輸出最小的標準差是多少。
標準差的介紹:標準差是多個數與它們平均數差值的平方平均數,一般用於刻畫這些數之間的“偏差有多大”。形式化地說,設第 i 個人付的錢爲 bi 元,那麼標準差爲 : [參見p1.png]
【輸入格式】
從標準輸入讀入數據。第一行包含兩個整數 n、S;
第二行包含 n 個非負整數 a1, ..., an。【輸出格式】
輸出到標準輸出。輸出最小的標準差,四捨五入保留 4 位小數。
保證正確答案在加上或減去 10^−9 後不會導致四捨五入的結果發生變化。【樣例1輸入】
5 2333
666 666 666 666 666【樣例輸出】
0.0000【樣例解釋】
每個人都出 2333/5 元,標準差爲 0。再比如:
【樣例輸入】
10 30
2 1 4 7 4 8 3 6 4 7【樣例輸出】
0.7928【數據說明】
對於 10% 的數據,所有 ai 相等;
對於 30% 的數據,所有非 0 的 ai 相等;
對於 60% 的數據,n ≤ 1000;
對於 80% 的數據,n ≤ 10^5;
對於所有數據,n ≤ 5 × 10^5, 0 ≤ ai ≤ 10^9。
資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。注意:
main函數需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要調用依賴於編譯環境或操作系統的特殊函數。
所有依賴的函數必須明確地在源文件中 #include <xxx>
不能通過工程設置而省略常用頭文件。提交程序時,注意選擇所期望的語言類型和編譯器類型。
二、思路
沒什麼特別的思路,特別需要注意的是,有的人即使是AA他還是付不起平均AA的價錢,所以需要把他擁有的所有錢交出來,然後重新計算平均數,重複上述步驟。
我們把每個人的餘款,從小到大升序排序,因爲前面的人不夠錢,會導致後面需要AA的錢擡高,因此我們先考慮錢少的人,因爲後面我們也需要重新計算平均值。
三、題解
#include <iostream> #include <algorithm> #include <cmath> using namespace std; int main() { int num_of_people;//人數 int total_money;//總需要付款 int each_afford[500001];//每個人餘款 cin >> num_of_people; cin >> total_money; for (int i=0;i<num_of_people;i++) { cin >> each_afford[i]; } sort(each_afford,each_afford+num_of_people);//將每個人餘款升序排序 double avg = total_money*1.0 / num_of_people;//計算初始平攤要給的錢 double newavg = avg;//新的平均值 double ans=0;//方差 for (int i=0;i<num_of_people;i++) { if(each_afford[i] < newavg)//有的人連AA都給不起,讓他們把現有的錢全給了 { ans = ans + pow((each_afford[i] - avg),2);//此時的方差 total_money = total_money - each_afford[i];//減掉給不起平攤的人的所有餘款 newavg = total_money*1.0 /(num_of_people-i-1);//減掉給不起平攤的錢之後算的平均值 } else { ans+=(num_of_people-i)*pow(newavg-avg,2); break; } } ans=sqrt(ans/num_of_people); printf ("%.4lf\n",ans); return 0; }
四、結果
5 2333
666 666 666 666 666
0.0000Process finished with exit code 0
10 30
2 1 4 7 4 8 3 6 4 7
0.7928Process finished with exit code 0