SRM 504.5 Div1 medium TheJackpotDivOne
問題概要
47人の人がいる。
あなたは10^18円くらいお金をもっている。
みんなそれぞれお金を持ってる。
一番お金が少ない人に対して、全員の平均より大きいの最小の整数円
になるようにお金をわたす。
たりない場合はありったけ渡す。
お金がある間繰り返す。
最終的にこの人たちの所持金を答えよ。
解法
実際にやる。
実際にやると、あることに気づく。
- 最大の所持金は全員のお金が一致するまで変化しない
- 全員が一致すると、全員に1円ずつ、順番にお金がなくなるまで渡せばよい。
そして、
- 全員の所持金が一致するまでそんなに時間がかからない。
ではなぜか。
それは、
- 最低でも、一番小さい値と一番大きい値の差の1/47は一番小さい値は増える。
つまるところ、
だいたい、47 * 47回繰り返せば全部一致する。
全部一致してからは、
- 全員が一致すると、全員に1円ずつ、順番にお金がなくなるまで渡せばよい。
ので、計算で求められる。
平均の計算がlong longでもあふれるので、工夫して平均とったほうがいい。
ソース
#include<algorithm> #include<vector> #define REP(i,b,n) for(int i=b;i<(int)n;i++) #define rep(i,n) REP(i,0,n) #define ALL(C) (C).begin(),(C).end() #define FOR(it,o) for(__typeof((o).begin()) it=(o).begin(); it!=(o).end(); ++it) using namespace std; long long ave(vector<long long> v){ unsigned long long sum = 0; unsigned long long ave = 0; FOR(it, v){ ave += *it/v.size(); sum += *it%v.size(); } unsigned long long ret = ave + sum / v.size() + 1; return ret; } class TheJackpotDivOne { public: vector<long long> find(vector<long long> money, long long n) { sort(ALL(money)); while(money.front() != money.back() && n > 0){ long long A = ave(money); long long D = A - money.front(); money.front() += min(D, n); n -= min(n, D); sort(ALL(money)); } if(n <= 0)return money; FOR(it, money){ *it += n / money.size(); } sort(ALL(money)); int ret = n % money.size(); rep(i, ret){ money[i]++; } sort(ALL(money)); return money; } };