CF131C题解

传送门:https://codeforces.com/problemset/problem/134/C

关注到题目的两个限制:1. 一个人只能与另外同一人交换一张卡牌。2. 一个人只能交换自己原来颜色的卡牌。

对于2条限制条件,显然有贪心思路:尽量让更多的人手持原有的卡牌。对于当前待交换的卡牌,一种构造思路,我们每次贪心选取手中拥有原有牌最多的人进行交换是最优的。

因为如果一个人手中原有的牌被取完就无法与其他人进行交换,显然比从拥有更多原有牌中取更劣。

此过程可以用大根堆维护,当一个人需要交换的卡牌比堆内剩余人数更多则不合法(为满足限制1)。

总时间复杂度 \(O((n+s)log_{2}n)\)

#include <bits/stdc++.h>

using namespace std;

inline int read() {
    char c;
    bool flag = false;
    while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
    int res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

const int _ = 2e5 + 1;

struct Node {
    int val, id;

    bool operator<(const Node &o) const { return val < o.val; }
} a[_];

vector<pair<int, int>> ans;

int main() {
    int n = read(), s = read();
    priority_queue<Node> q;
    for (int i = 1; i <= n; ++i) {
        a[i].val = read(), a[i].id = i;
        if (a[i].val) q.push(a[i]);
    }
    while (!q.empty()) {
        Node o = q.top();
        q.pop();
        if (o.val > q.size()) {
            puts("No");
            return 0;
        }
        vector<Node> tmp;
        while (o.val) {
            Node y = q.top();
            q.pop();
            ans.push_back(make_pair(y.id, o.id));
            --o.val;
            --y.val;
            if (y.val) tmp.push_back(y);
        }
        for (Node k: tmp) q.push(k);
    }
    puts("Yes");
    printf("%zu\n", ans.size());
    for (auto p: ans) printf("%d %d\n", p.first, p.second);
    return 0;
}
posted @ 2024-10-07 20:04  Jefferyzzzz  阅读(25)  评论(0)    收藏  举报