D. Productive Meeting-Codeforces Round #744 (Div. 3

原文链接Problem - D - Codeforces

D. Productive Meeting

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

An important meeting is to be held and there are exactly nn people invited. At any moment, any two people can step back and talk in private. The same two people can talk several (as many as they want) times per meeting.

Each person has limited sociability. The sociability of the ii-th person is a non-negative integer aiai. This means that after exactly aiai talks this person leaves the meeting (and does not talk to anyone else anymore). If ai=0ai=0, the ii-th person leaves the meeting immediately after it starts.

A meeting is considered most productive if the maximum possible number of talks took place during it.

You are given an array of sociability aa, determine which people should talk to each other so that the total number of talks is as large as possible.

Input

The first line contains an integer tt (1≤t≤10001≤t≤1000) — the number of test cases.

The next 2t2t lines contain descriptions of the test cases.

The first line of each test case description contains an integer nn (2≤n≤2⋅1052≤n≤2⋅105) —the number of people in the meeting. The second line consists of nn space-separated integers a1,a2,…,ana1,a2,…,an (0≤ai≤2⋅1050≤ai≤2⋅105) — the sociability parameters of all people.

It is guaranteed that the sum of nn over all test cases does not exceed 2⋅1052⋅105. It is also guaranteed that the sum of all aiai (over all test cases and all ii) does not exceed 2⋅1052⋅105.

Output

Print tt answers to all test cases.

On the first line of each answer print the number kk — the maximum number of talks possible in a meeting.

On each of the next kk lines print two integers ii and jj (1≤i,j≤n1≤i,j≤n and i≠ji≠j) — the numbers of people who will have another talk.

If there are several possible answers, you may print any of them.

Example

input

Copy

8
2
2 3
3
1 2 3
4
1 2 3 4
3
0 0 2
2
6 2
3
0 0 2
5
8 2 0 1 1
5
0 1 0 0 6

output

Copy

2
1 2
1 2
3
1 3
2 3
2 3
5
1 3
2 4
2 4
3 4
3 4
0
2
1 2
1 2
0
4
1 2
1 5
1 4
1 2
1
5 2

-------------------------------------------------------------------------------------------------------------

非常有意思的一道贪心题,刚开始还以为是最大最小组合来着,结果不是...

发现这样做会导致部分位置全是0,部分位置剩下好多没用到;

每次选择两个非零的数字,当不存在两个非零数字时,被迫结束。

我们要让次数最多,其实就是在每次减1的情况下,让两个非0的数字最多,让次数退化为0的进程慢一些,长一些。选择两个小的和选择两个大的相比,两者贡献相同,但前者势必会加速退化的进程,最终导致孤立点存在。比如 1 2 3

我们选择 1 3对话显然不如 2 3对话 。推测选择最大与次大进行对话,反证一下,如果不是这样,

那我们选择小一些的进行对话,造成0的个数势必会越来越多,越来越快,最终很可能剩下某个孤立点没有减完。所以我们每次选最大和次大交谈,是一直交谈完还是交谈一次?因为交谈完势必会改变最值情况,所以我们取一次放进队列一次;

采用优先队列和结构体结合,重载运算符让cnt大的在顶部,建立数组存储答案,注意清空栈和及时退出循环的操作

# include <iostream>
# include<algorithm>
# include<cstring>
# include<map>
# include<queue>

using namespace std;
typedef long long int ll;


int a[200000+10];
struct node
{
    int id,cnt;
    friend bool operator<(node a,node b)
    {
        return a.cnt<b.cnt;
    }
};
priority_queue<node>q;
int ans1[1000000];
int ans2[1000000];
int len1,len2;
int  main()
{

    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        ll ans=0;
        len1=0;
        len2=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            struct node head;
            head.cnt=a[i];
            head.id=i;
            q.push(head);
        }

        while(!q.empty())
        {
            if(q.top().cnt==0)
            {
                break;
            }
            struct node tail1,tail2;
            tail1.cnt=q.top().cnt;
            tail1.id=q.top().id;
            q.pop();
             if(q.top().cnt==0)
            {
                break;
            }
            tail2.cnt=q.top().cnt;
            tail2.id=q.top().id;
            q.pop();

            ans1[len1]=tail1.id;
            ans2[len2]=tail2.id;
            len1++;
            len2++;
            tail1.cnt--;
            tail2.cnt--;
            q.push(tail1);
            q.push(tail2);
            ans++;
        }

        cout<<ans<<'\n';

        for(int i=0;i<len1;i++)
        {
            cout<<ans1[i]<<" "<<ans2[i]<<'\n';
        }

        while(!q.empty())
        {
            q.pop();
        }
    }


    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值