題目大意:
給你一個長度爲 \(n\),值域在 \([1,n]\) 的序列 \(a\),每次操做能夠將一個位置的數替換爲當前序列的 \(MEX\),請你讓序列變成一個單調不降的序列,要求操做數在 \(2n\) 之內。
輸出操做數和每次操做對應的位置,不要求操做數最少。code
既然不要求操做數最少,那麼咱們就能夠嘗試構造一個特殊的序列,好比 \(0,0,\cdots,0\),\(0,1,\cdots,n-1\) 或 \(1,2,\cdots,n\) 等。
第一種實現太難了些,因此咱們嘗試後兩種。
以 \(1,2,\cdots,n\) 爲例。
首先,當一個數符合要求後,咱們顯然不會去改它。就算是出現了其餘數都符合要求(指知足咱們想要的結果,下同),剩一個數不一樣的狀況,咱們只要先讓他變成當前的 \(MEX\),若是當前 \(MEX\) 恰好是咱們想要的,就直接賦值完事,不然的話這個 \(MEX\) 必定爲 \(0\),那麼賦值以後就又變回第一種狀況了,由於其餘的數都已經把前面的那些數都填掉了。
接下來咱們對 \(MEX\) 分類討論。get
當 \(MEX \not= 0\) 時,咱們直接讓 \(a_{MEX}=MEX\) 便可。
當 \(MEX = 0\) 時,咱們就把他賦到一個不符合要求的數中去。string
這樣最後必定能獲得咱們想要的序列,接下來來檢驗他可否在 \(2n\) 次操做內完成。
顯然一個數最多隻會被操做兩次。
由於當把這個數賦值爲 \(0\) 後,除非讓他符合要求,不然不會改變他,由於這時 \(MEX\) 不可能會等於 \(0\)(只有等於 \(0\) 時纔可能對他再作一次操做)。
因而操做次數最多爲 \(2n\),符合題意。it
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int T,n,a[1005]; bool over[1005];//over[i]表示a[i]是否符合要求 int cnt,len,ans[2005];//cnt存有多少個數符合要求,len和ans存答案。 int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); cnt=len=0; memset(over,false,sizeof(over)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==i) over[i]=true,cnt++; } while(cnt<n) { int mex; bool m[1005]; memset(m,0,sizeof(m)); for(int i=1;i<=n;i++) m[a[i]]=true; for(int i=0;i<=n;i++) if(!m[i]){mex=i;break;} if(mex==0) { for(int i=1;i<=n;i++) if(!over[i]){a[i]=0;ans[++len]=i;break;} continue; } a[mex]=mex; over[mex]=true; ans[++len]=mex; cnt++; } printf("%d\n",len); for(int i=1;i<=len;i++) printf("%d ",ans[i]); puts(""); } return 0; }