読者です 読者をやめる 読者になる 読者になる

mayoko’s diary

プロコンとかいろいろ。

SRM 535 div1 med: FoxAndBusiness

解法

とりあえずいろいろ書いてみましょう。

0, 1, ..., K-1 の社員を選択するとします。この時, ability の和を A とすると, 各社員は等しい時間働くので, 各社員のはたらく時間は totalWork / A です。で, 各社員 i は, 全体の仕事の内 ai/A だけの仕事をこなすので, 給料は pi * (ai / A) * totalWork だけ払います。結局, 合計コストは
totalWork * sum((3600 + pi*ai)/A) となります。totalWork は固定なので, これは sum((3600 + pi*ai)/A) の最小化問題になります。これはよくある「(目標値) = x として x について二分探索する」というテクが使えますね。

sum((3600 + pi*ai)/A) <= x という条件は, sum(3600 + pi*ai) <= x*sum(ai) i.e. sum((x-pi)*ai) >= 3600*K と同値です。これを満たすかで x の二分探索をしましょう。

bool check(double x, const int K, const vector<int>& a, const vector<int>& p) {
    int N = a.size();
    vector<double> v(N);
    for (int i = 0; i < N; i++) v[i] = (x-p[i])*a[i];
    sort(v.rbegin(), v.rend());
    double sum = 0;
    for (int i = 0; i < K; i++) sum += v[i];
    return sum >= 3600*K;
}

class FoxAndBusiness {
public:
    double minimumCost(int K, int totalWork, vector <int> a, vector <int> p) {
        double low = 0, high = 1e9;
        for (int i = 0; i < 100; i++) {
            const double med = (low+high)/2;
            if (check(med, K, a, p)) high = med;
            else low = med;
        }
        return totalWork * high;
    }
};