将其连有向边$(i,c_{i})$,由于每一个点出入度都为1,那么必然构成若干个环
对于每一个环,从一点出发,将搜到的点依次记录下来(直至返回自己),记作$v_{1},v_{2},...,v_{k}$,那么就有$c_{v_{i}}=v_{i+1}$(特别的,$c_{v_{k}}=v_{1}$)
显然可以将其看作一个${1,2,...,k}$到${v_{1},v_{2},...,v_{k}}$的映射,即可以简化为${2,3,...,n,1}$如何解决,有一个$n+1$次的做法,具体操作过程如下:$(2,n)$,$(3,n)$,...,$(n-1,n)$,$(1,n)$,$(1,2)$,$(2,n)$
(特别的,当$n=2$,再找一个无关的数,参考样例中做法即可,也是3次)
如果每一个环都需要加1,那么最终次数就是$n+环数 $,显然次数过多
对于两个大小分别为$x$和$y$的环,类似上面将其描述为${2,3,...,x,1,x+2,...,x+y,x+1}$,我们可以用$x+y$次将其解决,具体操作过程如下:$(x,x+y)$,$(1,x+y)$,$(2,x+y)$,...,$(x-1,x+y)$,$(x+1,x)$,$(x+2,x)$...,$(x+y-1,x)$,$(x,x+y)$
由此,将两个环配对,最终至多剩下一个环,再用前面的方式即可,至多$n+1$次
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define mp make_pair 5 vector<int>v[N]; 6 vector<pair<int,int> >ans; 7 int n,m,a[N],vis[N]; 8 void dfs(int k){ 9 if (vis[k])return; 10 v[m].push_back(k); 11 vis[k]=1; 12 dfs(a[k]); 13 } 14 int main(){ 15 scanf("%d",&n); 16 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 17 for(int i=1;i<=n;i++) 18 if (!vis[i]){ 19 m++; 20 dfs(i); 21 if (v[m].size()==1)v[m--].clear(); 22 } 23 for(int i=1;i<m;i+=2){ 24 int x=v[i].size(),y=v[i+1].size(); 25 ans.push_back(mp(v[i][x-1],v[i+1][y-1])); 26 for(int j=0;j+1<x;j++)ans.push_back(mp(v[i][j],v[i+1][y-1])); 27 for(int j=0;j+1<y;j++)ans.push_back(mp(v[i+1][j],v[i][x-1])); 28 ans.push_back(make_pair(v[i].back(),v[i+1].back())); 29 } 30 if (m&1){ 31 if (v[m].size()==2){ 32 int x=1; 33 if (v[m][0]==1){ 34 if (v[m][1]>2)x=2; 35 else x=3; 36 } 37 ans.push_back(mp(v[m][0],x)); 38 ans.push_back(mp(x,v[m][1])); 39 ans.push_back(mp(x,v[m][0])); 40 } 41 else{ 42 int x=v[m].size(); 43 for(int i=1;i+1<x;i++)ans.push_back(mp(v[m][i],v[m][x-1])); 44 ans.push_back(mp(v[m][0],v[m][x-1])); 45 ans.push_back(mp(v[m][0],v[m][1])); 46 ans.push_back(mp(v[m][1],v[m][x-1])); 47 } 48 } 49 printf("%d ",ans.size()); 50 for(int i=0;i<ans.size();i++)printf("%d %d ",ans[i].first,ans[i].second); 51 for(int i=0;i<ans.size();i++){ 52 int x=ans[i].first,y=ans[i].second; 53 swap(a[x],a[y]); 54 a[x]*=-1,a[y]*=-1; 55 } 56 for(int i=1;i<=n;i++)assert(a[i]==i); 57 }