[cf1491G]Switch and Flip

将其连有向边$(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 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14471320.html