1. 程式人生 > 實用技巧 >NC50439 tokitsukaze and Soldier(貪心)

NC50439 tokitsukaze and Soldier(貪心)

題目連結

題目大意

  略

解題思路

  使用兩個優先佇列,第一個優先佇列以v為第一優先順序,s為第二優先順序從大到小排序,第二個優先佇列以s為第一優先順序,v為第二優先順序從小到大排序。對於第一個優先佇列堆頂的一對(v,s)來說,如果s我們選出的所有數的數量小,就不需要他了,因為我們以v的大小為第一優先順序,加上他最少需要減去一個比他更大的數,然後我們把符合條件的數加入第二個優先佇列。
  由於可能有前面v比較大的數s比較小,當s最小的數的s已經比當前選出的數小時,需要去掉這個數來給其他的數騰出位置,這就是第二個優先佇列的意義。

程式碼

const int maxn = 1e5+10;
const int maxm = 1e4+10;
struct INFO {
    int v, s;
    bool operator < (const INFO &a) const {
        return v==a.v ? s<a.s:v<a.v;
    }
};
struct INFO2 {
    int v, s;
    bool operator < (const INFO2 &a) const {
        return s==a.s ? v>a.v:s>a.s;
    }
};
int n;
priority_queue<INFO> pq;
priority_queue<INFO2> pq2;
int main(void) {
    cin >> n;
    ll sum = 0, ans = 0;
    for (int i = 0, a, b; i<n; ++i) {
        scanf("%d%d", &a, &b);
        pq.push({a, b});
        //cout << pq.top().v << endl;
    }
    while(!pq.empty()) {
        int a = pq.top().v, b = pq.top().s; pq.pop();
        if (b<=pq2.size()) continue;
        pq2.push({a, b});
        sum += a;
        if (pq2.top().s<pq2.size()) sum -= pq2.top().v, pq2.pop();
        ans = max(ans, sum);
    }
    cout << ans << endl;
    return 0;
}