2018 雅禮國慶集訓
阿新 • • 發佈:2018-12-13
Merchant
有n個物品,第i個物品有兩個屬性ki , bi,表示它在時刻x的價值為ki × x + bi . 當前處於時刻0,你可以選擇不超過m個物品,使得存在某個整數時刻t, t ≥ 0,你選擇的 所有物品的總價值大於等於S. 給出S,求t的最小值。
很容易想到幾個物品加起來的時候,價值是一個一次函式(合併同類項)
然後畫一下圖可以發現(然而我考試時並沒有發現),在同一個x座標下對應一個最大值,這個最大值是先減後增的。
所以我們可以先判斷一下0時刻,如果可以就輸出0,不然就二分
每一次判斷的時候算出此時的價值,然後用一個騷操作nth_element, 可以求出前m個最大的,複雜度O(n)
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; const int MAXN = 1e6 + 10; int k[MAXN], b[MAXN], n, m; ll c[MAXN], s; bool check(int t) { ll sum = 0; REP(i, 0, n) c[i] = 1ll * k[i] * t + b[i]; nth_element(c, c + m, c + n, greater<ll>()); //從大到小 REP(i, 0, m) if((sum += c[i]) >= s) //注意可能後面的值為負,所以不一定全部加完才最大 return true; return false; } int main() { scanf("%d%d%lld", &n, &m, &s); REP(i, 0, n) scanf("%d%d", &k[i], &b[i]); if(check(0)) { puts("0"); return 0; } int l = 0, r = 1e9 + 1; while(l + 1 < r) { int m = (l + r) >> 1; if(check(m)) r = m; else l = m; } printf("%d\n", r); return 0; }