CF1364C 【Ehab and Prefix MEXs】
題目翻譯:
剛開始給你一個空的陣列 \(b\ (b_i \le 10^6)\) , 每次可以將任意一個數填入該陣列中 , 但是必須保證第 \(i\) 次放完後該陣列的 \(\text{mex}\) 為 \(a_i \ (a_i\le 10^5)\)。請你求出放數字的順序。若沒有合法的順序就輸出 -1
。
資料保證 \(a\) 陣列單調上升。
一個數組的 \(mex\) 即在這個陣列中最小的沒有出現過的自然數。
思路:
CF 的傳統構造題 , 其實很好想。
顯然,如果 \(a_i>=i\) 那顯然是沒有合法的順序的,因為如果要使第 \(i\) 次的 \(\text{mex}=a_i\) , 就至少要放 \(a_i\)
那麼我們可以將 \(b_i\) 分成兩種:
- 放置對 \(a_i\) 有影響的數字。
- 放置對 \(a_i\) 暫時沒有影響的數字。
因為有影響的數字定下來了就無法改變,那麼我們可以記錄一個指標 \(now\) ,指向暫時沒有影響的 \(a_i\) 中 \(i\) 最小的元素。
顯然,所填的數一定也是單調遞增的,所以還可以在記錄一個標記 \(num\) 表示現在已經填到了數字幾。
這樣的話我們每讀到一個 \(a_i\) ,就要判斷 \(num\) 是否已經到達了 \(a_i-1\) ,如果沒有就需要將從 \(num \sim a_i-1\)
因為越 \(i\) 越小,留的餘地就越大,所以每當需要填數時,就把他填在 \(now\) 所指向的位置,並將這個 \(b_i\) 納入對 \(a_i\) 有影響的那一類中。
但是需要注意的點是,當 \(a_i\) 這個數首次出現時,\(b_i\) 一定是對 \(a_i\) 有影響的,因為第 \(i\) 次填數導致了 \(a_i\) 的變化。
而那些直到最後也沒有對 \(a_i\) 造成影響的 \(b_i\) ,我們可以把他們全部設為 \(10^6\) ,因為 \(a_i \le 10^5\) 而 \(b_i \le 10^6\),所以填 \(10^6\)。一定不會對 \(a_i\)
Code:
#include<bits/stdc++.h>
using namespace std;
int read()
{
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
return ans*f;
}
const int N=1e5+5;
int n,a[N],b[N],have,num,now=1;
int main()
{
memset(b,-1,sizeof(b));
// 將 b 陣列全部設為暫時無影響
n=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<=n;++i)
{
if(a[i]>i)
// 若 a_i > i 則一定無解
{
printf("-1\n");
return 0;
}
for(;num<=a[i]-1;++num)
// 將 num ~ a_i-1 裡的數全部填上
{
if(b[i]==-1)
// 如果 a_i 首次出現,則 b_i 一定有影響
b[i]=num;
else
{
while(b[now]!=-1)
// 找到暫時沒有影響中 i 最小的位置
now++;
// 將這個位置填上;
b[now]=num;
}
}
num=a[i];
}
for(int i=1;i<=n;++i)
if(b[i]==-1) printf("%d ",1000000); // 最後也沒有影響的直接輸出10^6
else printf("%d ",b[i]);
return 0;
}