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