CF1579D Productive Meeting 黄 题解

题目传送门

Part1. 思路

这一题要找到交流次数最多的一组答案,所以理所当然地想到要尽可能的多用交流次数。

所以要尽可能的多匹配还有交流次数的人去交流。

但是如果随便匹配,就会出现这样的情况:

1
3
1 2 3

这组数据的答案很明显:

3
1 3
2 3
2 3

假如随便匹配,就可能得到这样的答案:

2
1 2
2 3

出现这种情况的原因是什么呢?

很容易发现,随便匹配得出的过程中,在前两人已经用完交流次数时,交流次数最多的第 \(3\) 个人的交流次数还有 \(2\),很明显没有物尽其用,出现了浪费。

所以需要尽量规避这种情况。

然后就会想到让交流次数最多的两人进行交流,来获得最多的交流次数。

这时候就又会有两种不同的想法:

  1. 将交流次数最多的两人中交流次数较少的那个人的交流次数用完,再找新的交流次数最多的两人。

  2. 将交流次数最多的两人的交流次数各使用 \(1\),然后找新的交流次数最多的两人。

如果使用想法一,在下面的数据中就会出错:

1
5
5 5 5 5 5

正确答案为:

12
4 5
2 3
1 5
3 4
1 2
4 5
2 3
1 5
3 4
1 2
4 5
2 3

但是用想法一得出的答案是:

10
4 5
4 5
4 5
4 5
4 5
2 3
2 3
2 3
2 3
2 3

很明显,有一个人的交流次数完全没有使用,完全被浪费。

所以也需要避免出现这种情况。

现在我们便得到了正解:

维护一个大根堆,将所有的有交流次数的人压入队列,当队列中还至少有两个人时,将队首的两人弹出,将他们的交流次数 \(-1\),如果还有剩余的交流次数,就再将它们压回队列。

Part2. 代码

#include <bits/stdc++.h>
using namespace std;

int t,n,ans,a[200010];
pair<int,int> tot[200010];

int main () {
    cin>> t;
    while (t--) {
        cin>> n;
        priority_queue<pair<int,int> > q;
        for (int i=1;i<=n;i++) {
            cin>> a[i];
            if (a[i]>0) q.push ({a[i],i});
        }
        ans=0;
        while (q.size ()>=2) {
            pair<int,int> u=q.top ();
            q.pop ();
            pair<int,int> v=q.top ();
            q.pop ();
            tot[++ans]={min (u.second,v.second),max (u.second,v.second)};
            u.first--;
            v.first--;
            if (u.first) q.push (u);
            if (v.first) q.push (v);
        }
        cout<< ans<< "\n";
        for (int i=1;i<=ans;i++)
            cout<< tot[i].first<< " "<< tot[i].second<< "\n";
    }
    return 0;
}

AC记录

posted @ 2025-03-04 20:51  M_CI  阅读(36)  评论(0)    收藏  举报