這種題目很多都和逆序對數有關(我也不知道為甚麼XD),可以發現,操作a可以視為將b操作的基準點往前移一格,那剩下的就是考慮要依序在哪幾點進行b操作了
首先,先決定一點(這點怎麼決定等一下再說www),把1移到那個地方,接著會說明,如果有解,對剩下的2,3,...N存在一系列操作使得任意操作都不會動到1
接下來往逆序數對思考吧,可以發現,操作b在任何情況下都不改變逆序對數的奇偶性,操作a就只有N是偶數的情況下才會改變逆序對數的奇偶性
若數列已經排序好,逆序對數為零(偶數),因此如果N是偶數,而逆序對數是奇數的話,無解
反之,如果N是奇數,逆序對數是奇數,則想成先把「排序好的序列做一次操作a」的情況弄出來(因為這時逆序對數是奇數),再做N-1次操作a還原
這等價於先把1放在N這個位置
如果逆序對數是奇數,就把1放在1這個位置
然後就可以透過好多次「對不同位置進行操作b(多次操作a和一次操作b的組合)」依序把2,3,...N-2排好了(當然,1是不能動的,要永遠待在1或N這個位置)
咦?如果這時候N-1和N的位置反過來了怎麼辦?
這是不可能發生的,因為前面的預處理已經將逆序對數弄成偶數了,上述情況的逆序對數是奇數哦XD~
然後,就不小心做完了(?)
記錄下每一個操作,轉換成題目要求的格式輸出,就很開心的WA了(?)
哦,因為我把'a'打成'A'了XDD
code:
#include<cstdio> #include<algorithm> #include<vector> #include<cassert> using namespace std; int N,S[2000],LOC[2000],CUR; vector<int>ANS; void Swap(int i,int j){swap(LOC[S[i]],LOC[S[j]]),swap(S[i],S[j]);} void OperateA(){ANS.push_back(0);CUR--;if(CUR<0)CUR+=N;} void OperateB(){ANS.push_back(1);Swap((CUR+1)%N,(CUR+2)%N),Swap(CUR,(CUR+1)%N);} void MoveCUR(const int target){while(CUR!=target)OperateA();} int InvPairs(){int ans=0;for(int i=0;i<N;i++)for(int j=i+1;j<N;j++)if(S[i]>S[j])ans++;return ans;} bool Solve() { if((N-1)%2==0&&InvPairs()%2==1)return false; CUR=0,ANS.clear(); int basis=0; if((N-1)%2==1&&InvPairs()%2==1){OperateA();basis=N-1;} for(int v=0;v+2<N;v++) { const int target=(basis+v)%N; while(LOC[v]!=target) { if((target+1)%N==LOC[v])MoveCUR(target),OperateB(),OperateB(); else MoveCUR(((LOC[v]-2)%N+N)%N),OperateB(); } // for(int i=0;i<N;i++)printf("%d ",S[i]);puts(""); // for(int i=0;i<N;i++)printf("%d ",LOC[i]);puts("");puts(""); } for(int v=0;v<N;v++)assert(LOC[v]==(LOC[0]+v)%N),assert(S[LOC[v]]==v); MoveCUR(LOC[0]); return true; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d",&N)==1) { for(int i=0;i<N;i++)scanf("%d",&S[i]),LOC[--S[i]]=i; if(!Solve())puts("NIE DA SIE"); else { vector<int>ansa,ansb; for(int i=0;i<(int)ANS.size();) { int cnt=0; while(i+cnt<(int)ANS.size()&&ANS[i+cnt]==ANS[i])cnt++; ansa.push_back(cnt),ansb.push_back(ANS[i]); i+=cnt; } assert((int)ansa.size()<=N*N); printf("%d\n",(int)ansa.size()); for(int i=0;i<(int)ansa.size();i++) { if(i)putchar(' '); printf("%d%c",ansa[i],'a'+ansb[i]); } puts(""); } break; } return 0; }
沒有留言:
張貼留言
歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原
注意:只有此網誌的成員可以留言。