Codeforces Round #762 (Div. 3) E. MEX and Increments

https://codeforces.com/contest/1619/problem/E 

翻译:

Dmitry有一个𝑛非负整数数组𝑎1,𝑎2,…,𝑎𝑛。

在一次操作中,Dmitry可以选择任意索引𝑗(1≤𝑗≤𝑛),并将元素𝑎𝑗的值增加1。他可以多次选择相同的索引𝑗。

对于从0到𝑛的每个𝑖,确定Dmitry是否可以使数组的MEX恰好等于𝑖。如果可能,那么确定最少的操作数。

数组的MEX等于数组中不存在的最小非负整数。例如,数组[3,1,0]的MEX值为2,数组[3,3,1,4]的MEX值为0。

输入
输入数据的第一行包含一个整数𝑡(1≤𝑡≤104)——输入中的测试用例的数量。

下面是测试用例的描述。

每个测试用例描述的第一行包含一个整数𝑛(1≤𝑛≤2⋅105)——数组𝑎的长度。

每个测试用例描述的第二行包含𝑛整数𝑎1,𝑎2,…,𝑎𝑛(0≤𝑎𝑖≤𝑛)-数组𝑎的元素。

可以保证测试中所有测试用例𝑛的值之和不超过2⋅105。

输出
对于每个测试用例,输出𝑛+1整数-𝑖-th number等于可以使数组MEX等于𝑖(0≤𝑖≤𝑛)的最小操作次数,如果不能这样做,则为-1。

例子
inputCopy
5
3.
0 1 3
7
0 1 2 3 4 3 2
4
3 0 0 0
7
4 6 2 3 5 0 5
5
4 0 1 0 4
outputCopy
1 10 10 -1
1 1 2 2 1 0 2 6
3 0 1 4 3
1 0 -1 -1 -1 -1 -1 -1 -1 -1
2 1 0 2 -1 -1
请注意
在第一组示例输入中,𝑛=3:

要得到MEX=0,执行一次增量就足够了:𝑎1++;
要得到MEX=1,执行一次增量就足够了:𝑎2++;
对于给定的数组,MEX=2,因此不需要执行增量;
通过执行增量不可能得到MEX=3。

思路:

MEX,我们很容易得到一个结论,如果前边比较小的数构不成的时候,那么后边都构不成,因为是未出现的i最小的非负整数,所以我们一旦有一个-1,那么后边就全是-1啦。

然后我们来分析一下,构成的条件是什么,比如说 5,那么它的前边至少要有一个0 1 2 3 4,4的构成条件是0 1 2 3,同理我们可以这样子往前推,直接到0,0的构成条件,只要没有0就好了对吧,所以0的花费就是0出现的个数,那么1呢,如果0不能构成那么1就直接是-1,所以我们直接讨论在前边可以构成的前提下,来构成现在的条件。

1的话,我们的花费也就是1的个数(因为已经在0被构成的前提下),接下来看2,2的话就是在有0 1的情况下加上2的个数,但是我们可能会有没有1 有两个0 的情况,那么我们就需要将一个0 变成1,然后加上2的个数,如果有一个0呢,那么我们就可以直接-1了。

同理,构成三需要2,如果比其小的是0 0 0,那么我们就需要将其变成 0 1 2,对吧,然后花费成本+3的个数,变成0 1 2,如果是3个0的时候,在前边2的情况下,我们就已经将其变成了 0 1 0,所以我们每次只需要在其成本上累加。有可能比其小的数不是0,我们需要将其变大,最小成本就是最大的数去变化,所以我们这里用优先队列优化,也可以用栈,因为我们从小到大,后进入的肯定是最大的,已经变化过的就要固定了,不能再变化pop掉,这思路就很清晰了。

嗲吗:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
#include<stack>
using namespace::std;
typedef long long  ll;
int n,t;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

int a[200005];
int w;
void solv(){
    cin>>n;
    map<int,ll>q;
    for (int i =1; i<=n; i++) {
        cin>>w;
        q[w]++;
    }
    bool flag=false;
    ll bl=0;
    priority_queue<int>ff;
    for (int i =0; i<=n; i++) {
        if (flag) {
            printf("-1 ");
        }
        else
        {
            printf("%lld ",bl+q[i]);
        }
        for (int j =0; j<q[i]; j++) {
            ff.push(i);
        }
        if (ff.empty()) {
            flag=true;
        }
        else{
            bl+=i-ff.top();
            ff.pop();
        }
    }
    printf("\n");
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>t;
    while (t--) {
        solv();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值