Ehab and Prefix MEXs(STL, 思维,模拟)

Ehab and Prefix MEXs

原题链接:传送门

题目大意

给定一个数组a,长度为n,要求你找到一个数组b满足:

对于每一个 \(a_i = MEX(\{b_1 , b_2,...b_n\})\),

MEX 运算表示不在集合中的最小的非负整数。

分析

做的时候突然没有思路,现在理一下思路和做法。

首先先观察找规律,如果要在b[i] 上放一个元素,那么这个元素一定不在a[i]~a[n]中出现过,否则在后面就会产生矛盾。

那么我们可以用一个set集合,将所有从i位置以后(包括i)没有在a中出现过的数字存下来。每一次必然从这个set中取出一个数字存入数组b中再将这个数从set中删除。

我们来推里一下这个方法为什么是正确的:

首先如果对于 a[i-1] 成立的话,对于a[i],0~a[i]-1中一定已经被填满了,因为a[i] <= i,前面填了 i - 1 个数子,b又是按照从小到大的顺序存储的,所以只要b取a[i-1]即可满足条件。

如果a[i] == a[i-1] 时,那么继续取set中的第一个数即可。

实际上对于该问题:a[i] <= i 就解决了不可能没有解的情况

注意事项

认真分析,div2 C题一般都是STL的用法和一些基础的贪心dp冷静思考耐心观察一般都可以做出来的 加油

AC 代码

AC code

void slove()
{
	int n;cin >> n;
	vector<int> a(n);
	map<int,int> m;
	set<int> b;
	for(int i = 0;i < n ;i ++)
	{
		cin >> a[i];m[a[i]] = 1; 
	}
	for(int i = 0;i <= 2 * n;i ++)
	{
		if(m[i] == 0)b.insert(i);
	}
	for(int i = 0;i < n ;i ++)
	{
		if(i && a[i] != a[i-1])b.insert(a[i-1]);
		cout << *b.begin() << " ";
		b.erase(*b.begin());
	}
}

标程/优秀代码

#include <bits/stdc++.h>
using namespace std;
int a[100005],b[100005];
bool ex[100005];
int main()
{
	int n;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	memset(b,-1,sizeof(b));
	for (int i=1;i<=n;i++)
	{
		if (a[i]!=a[i-1])
		{
			b[i]=a[i-1];
			ex[b[i]]=1;
		}
	}
	ex[a[n]]=1;
	int m=0;
	for (int i=1;i<=n;i++)
	{
		while (ex[m])
		m++;
		if (b[i]==-1)
		{
			b[i]=m;
			ex[m]=1;
		}
		printf("%d ",b[i]);
	}
}
posted @ 2020-09-18 17:10  _starsky  阅读(202)  评论(0编辑  收藏  举报