1. 程式人生 > 實用技巧 >Ehab and Prefix MEXs(STL, 思維,模擬)

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