CF1579D Productive Meeting 黄 题解

题目传送门

Part1. 思路

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

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

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

1
3
1 2 3

这组数据的答案很明显:

3
1 3
2 3
2 3

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

2
1 2
2 3

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

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

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

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

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

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

  2. 将交流次数最多的两人的交流次数各使用 1 1 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 -1 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记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值