题解 CF1491G 【Switch and Flip】

SSerxhs

2021-03-01 13:24:00

Solution

把 $c_i$ 看成图上存在一条 $i\to c_i$ 的边,则每个点恰有一条入边一条出边,可以证明图构成若干个环。 考虑如何同时处理两个环。 可以这样构造(下为 $c_i$) 231 564 234 561 134 562 124 563 123 564 123 465 123 456 这里通过一开始一次多余的操作,使每个数字恰好被操作两次。 于是我们通过 $|S_1|+|S_2|$ 次操作处理了两个环 $S_1,S_2$。 考虑对于剩下那个环怎么处理,一个简单而错误的想法是直接借一个已经归位的自环处理。 然而整张图可能就是一个大环,这时并不能用这种方法。 我们模仿上面的过程进行构造。 23451 32451 42351 52341 这里同样是借助多做一次操作,使 234 归位。 然而这里 5 不能再归位了,因为 1 和 2 的操作次数会不对。 这里我们继续使用一次操作使 1 操作次数正确。 51342 15342 12345 至此,通过 $|S|+1$ 次操作,成功解决了环 $S$。 总操作次数至多为 $n+1$。 ```cpp #include <bits/stdc++.h> using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; std::mt19937 rnd(time(0)); inline int sj(int n) { unsigned int x=rnd(); return x%n+1; } #define rand fst template<typename typC> void read(register typC &x) { register int c=getchar(),fh=1; while ((c<48)||(c>57)) { if (c=='-') {c=getchar();fh=-1;break;} c=getchar(); } x=c^48;c=getchar(); while ((c>=48)&&(c<=57)) { x=x*10+(c^48); c=getchar(); } x*=fh; } template<typename typC> void write(register typC x) { if (x<0) putchar('-'),x=-x; static int st[100]; register int tp=1,y;st[1]=x%10;x/=10; while (x) y=x/10,st[++tp]=x-y*10,x=y;++tp; while (--tp) putchar(st[tp]|48); } template<typename typC> void write(register typC *a,register int num) { for (register int i=1;i<=num;i++) write(a[i]),putchar(i==num?10:32); } #define space(x) write(x),putchar(32) #define enter(x) write(x),putchar(10) const int N=1e6+2,M=1e6+2,p=998244353; inline void inc(register int &x,const int y) { if ((x+=y)>=p) x-=p; } inline void dec(register int &x,const int y) { if ((x-=y)<0) x+=p; } inline int ksm(register int x,register int y) { register int r=1; while (y) { if (y&1) r=(ll)r*x%p; x=(ll)x*x%p; y>>=1; } return r; } vector<int> bel[N]; char s[N]; int a[N],ed[N],st[N],ans[N][2]; int T,n,m,c,i,j,k,x,y,z,ass,la,tp; int main() { read(n); for (i=1;i<=n;i++) read(a[i]); for (i=1;i<=n;i++) if (!ed[i]) { ed[i]=i;bel[i].push_back(i); for (j=a[i];j!=i;j=a[j]) ed[j]=i,bel[i].push_back(j); } for (i=1;i<=n;i++) if (ed[i]==i) st[++tp]=i; for (i=1;i+1<=tp;i+=2) { x=st[i];y=st[i+1]; ans[++ass][0]=bel[x][0];ans[ass][1]=bel[y][0]; for (int i=1;i<bel[x].size();i++) ans[++ass][0]=bel[y][0],ans[ass][1]=bel[x][i]; for (int i=1;i<bel[y].size();i++) ans[++ass][0]=bel[x][0],ans[ass][1]=bel[y][i]; ans[++ass][0]=bel[x][0];ans[ass][1]=bel[y][0]; } for (;tp&1;) { if (bel[st[tp]].size()==1) break;x=st[tp]; if (bel[x].size()==2) { for (i=1;i<=n;i++) if (i!=bel[x][0]&&i!=bel[x][1]) break; ans[++ass][0]=bel[x][0],ans[ass][1]=i; ans[++ass][0]=bel[x][1],ans[ass][1]=i; ans[++ass][0]=bel[x][0],ans[ass][1]=i;break; } for (i=1;i+1<bel[x].size();i++) ans[++ass][0]=bel[x][0],ans[ass][1]=bel[x][i]; ans[++ass][0]=bel[x][1];ans[ass][1]=bel[x][bel[x].size()-1]; ans[++ass][0]=bel[x][0];ans[ass][1]=bel[x][bel[x].size()-1]; ans[++ass][0]=bel[x][1];ans[ass][1]=bel[x][0]; break; } printf("%d\n",ass); for (i=1;i<=ass;i++) printf("%d %d\n",ans[i][0],ans[i][1]); } ```