Codeforces 1364C Ehab and Prefix MEXs(贪心)

题目链接

题目大意

  给一个a数组,要求定义一个b数组,使得\(b_1\)~\(b_i\)之中没有出现的最小的数等于\(a_i\)

解题思路

  首先可以肯定的是,如果要给b数组填数的话,一定要优先填较小的数,我们这里用一个变量k来填。其次,后面要出现的数字不能用,但是前面出现过后面不会再出现的数可以用。因为要使得\(b_1\)~\(b_i\)之中没有出现的最小的数等于\(a_i\),所以我们每遍历一个\(a_i\)就把对应的\(b_i\)填上去就行了。这里我们就要分情况讨论。

当k与a_i相等

  我们先考虑把队列里面的一个数放到b数组里面之后队列里还有没有比\(a_i\)小的数,如果有,无解。如果队列为空说明之前有解的话,那么我们需要填一个比\(a_i\)大的数,并且这个数不会和\(a_i\)之后的数相等。这个\(a_i\)要用队列存起来,一旦有\(a_i\)比它大就要用上它。

当k比a_i小

  这时候我们必须填上一个比\(a_i\)小的数,如果我们队列里面有数的话,肯定是不行的,显然k要比队列里的数大,这样只放一个的话无解。同样的,如果我们放入一个k之后,k+1还是比\(a_i\)小也是不行的。还有一种情况就是我们要放到数后面还会出现,这样的话显然也是不行的。

当k比a_i大

  这种情况的话,我们先考虑把队列里面的一个数放到b数组里面之后队列里还有没有比\(a_i\)小的数,如果有,无解。如果队列是空的那就往k增大的方向找一个后面不会出现的数就行了。

const int maxn = 2e6+10;
int vis[maxn], arr[maxn];
queue<int> tmp;
vector<int> ans;
int main() {
    int n; scanf("%d",&n);
    for (int i = 0; i<n; ++i) {
        scanf("%d",&arr[i]);
        ++vis[arr[i]];
    }
    int tot = 0; bool flag = false;
    for (int i = 0; i<n; ++i) {
        if (tot<arr[i]) {
            if (!tmp.empty()&&tmp.front()<arr[i]) flag = true;
            if (vis[tot]) flag = true;
            ans.push_back(tot++);
            if (tot<arr[i]) flag = true;
        }
        else if (tot>=arr[i]) {
            if (!tmp.empty()&&tmp.front()<arr[i]) {
                if (vis[tmp.front()]) flag = true;
                ans.push_back(tmp.front()); tmp.pop();
                if (!tmp.empty()&&tmp.front()<arr[i]) flag = true;
            }
            else {
                if (tot==arr[i]) tmp.push(tot++);
                while(vis[tot]) {
                    tmp.push(tot);
                    tot++;
                }
                ans.push_back(tot++);
            }
        }
        --vis[arr[i]];
    }
    if (tot>1000000) flag = true;
    if (flag) {
        printf("-1\n");
        return 0;
    }
    for (int i = 0; i<n; ++i) printf(i==n-1?"%d\n":"%d ", ans[i]);
    return 0;
}
posted @ 2020-06-14 01:03  shuitiangong  阅读(151)  评论(0编辑  收藏  举报