[CSL 的魔法][求排序最少交换次数]

链接:https://ac.nowcoder.com/acm/contest/551/E
来源:牛客网
题目描述

有两个长度为 n 的序列,a0,a1,,an1a0,a1,…,an−1和 b0,b1,,bn1b0,b1,…,bn−1。CSL 有一种魔法,每执行一次魔法,可以任意挑选一个序列并任意交换序列中两个元素的位置。CSL 使用若干次魔法,得到最终的序列 a 和 b,并且想要让 a0b0+a1b1++an1bn1a0b0+a1b1+…+an−1bn−1的值最小化。求解 CSL 至少使用多少次魔法,能够达到最小化的目标。
输入描述:
第一行有一个整数 n,表示序列的长度。

接下来两行,每行有 n 个整数,分别表示初始序列 a 和 b。

输入数据保证每个序列里的数两两不同。
 
2n1e5
1ai,bi1e9
输出描述:
在一行输出一个整数,表示最少使用的魔法次数。
示例1
输入
2
1 2
1 2

输出
1
示例2
输入
2
1 2
2 1

输出
0
题意:两个数组,你每次可以交换任一个数组里两个元素的位置,求最小交换次数使a0b0+a1b1++an1bn1a0b0+a1b1+…+an−1bn−1的值最小化。
题解:易知应该令a数组最大*b数组最小..依次进行,所以问题变成了使a数组(或者b数组)变成一个有序(特定的顺序)数组的最小次数,而使数组变成有序的最小次数==数组大小-循环节数,这里的循环节数就是:举例:如1 4 5 2 6 3 的循环节数就是3,即【1】【4 2】【5 6 3】
 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdio>
 6 #include<vector>
 7 #include<queue>
 8 using namespace std;
 9 typedef long long ll;
10 struct pot{
11     int id;
12     int val;
13 }p[100005],p1[100005];
14 bool cmp(struct pot aa,struct pot bb){
15     return aa.val<bb.val;
16 }
17 int a[100005];
18 int main(){
19     int n;
20     scanf("%d",&n);
21     for(int i=1;i<=n;i++){scanf("%d",&p[i].val);p[i].id=i;}
22     for(int i=1;i<=n;i++){scanf("%d",&p1[i].val);p1[i].id=i;}
23     sort(p+1,p+1+n,cmp);
24     sort(p1+1,p1+1+n,cmp);
25     for(int i=1;i<=n;i++){
26         a[p1[n-i+1].id]=p[i].id;
27     }
28     int ans=0;
29     for(int i=1;i<=n;i++){
30         if(a[i]==i)ans++;
31     }
32     for(int i=1;i<=n;i++){
33         if(a[i]==i)continue;
34         ans++;
35         int xx=a[i];
36         while(a[xx]!=xx){
37             int t=a[xx];
38             a[xx]=xx;
39             xx=t;
40         }
41     }
42     cout<<n-ans<<endl;
43     return 0;
44 }
View Code
 
原文地址:https://www.cnblogs.com/MekakuCityActor/p/10637954.html