题目描述:
为什么前两题中没有出现小 G ? 因为小 G 去工地搬砖了。
现在小 G 面前从左到右放了 $n$ 块砖,第 $i$ 块砖重 $a_i$ 斤。小 G 的任务就是把这些砖头从左到右按重量从小到大排好顺序。如果说小 G 完成任务后从左到右第 $i$ 块砖重 $b_i$ 斤,那么必须满足 $b_i ≤ b_{i+1}$。小 G 身体瘦弱,每次搬运只能做到交换任意两块砖。因为工资是按搬运次数算的,小 G 希望在完成任务前能搬运尽量多次。但是因为有包工头盯着,又不能乱搬。如果一次搬运前有 $x$ 个 $i$ 满足 $a_i = b_i$,而搬运后有 $y$ 个 $i$ 满足 $a_i = b_i$ , $y$ 就必须大于 $x$,否则包工头就会发现小 G 故意不好好干然后把小 G 炒了。现在小 G 想知道他完成任务时最多搬运了几次。
思路:
对于 $ai!=bi$ 的点我们把 $ai$ 和 $bi$ 相连,
此时构成的联通块里如果有 $2$ 个种颜色的点,那么就会有点数 $/2$ 的贡献,因为每次只能两两不同的交换位置。
如果有大于 $2$ 个种颜色,那么每次可以选择仅让一个归回原位,直到只剩下两个点,不得不至多只有两种颜色时,答案为 $1$ ,所以这种情况贡献为点数 $-1$ 。
以下代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e6+5; int n,tot,fa[N],a[N],b[N],num[N],ans,sum[N]; map<int,int> m; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int getfa(int x){ if(!fa[x])return x; return fa[x]=getfa(fa[x]); } int main() { n=read(); for(int i=1;i<=n;i++)a[i]=b[i]=read(); sort(b+1,b+1+n); m[b[1]]=++tot; for(int i=2;i<=n;i++)if(b[i]!=b[i-1])m[b[i]]=++tot; for(int i=1;i<=n;i++){ if(a[i]!=b[i]){ int x=getfa(m[a[i]]),y=getfa(m[b[i]]); if(x==y)continue; fa[x]=y; } } for(int i=1;i<=n;i++){ if(a[i]!=b[i]){ sum[getfa(m[a[i]])]++; } } for(int i=1;i<=tot;i++)num[getfa(i)]++; for(int i=1;i<=tot;i++){ if(num[i]>2)ans+=max(sum[i]-1,0); else ans+=sum[i]/2; } printf("%d\n",ans); return 0; }