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;
}