[CSL 的魔法][求排序最少交换次数]
链接:https://ac.nowcoder.com/acm/contest/551/E
来源:牛客网
题目描述
有两个长度为 n 的序列,a0,a1,…,an−1a0,a1,…,an−1和 b0,b1,…,bn−1b0,b1,…,bn−1。CSL 有一种魔法,每执行一次魔法,可以任意挑选一个序列并任意交换序列中两个元素的位置。CSL 使用若干次魔法,得到最终的序列 a 和 b,并且想要让 a0b0+a1b1+…+an−1bn−1a0b0+a1b1+…+an−1bn−1的值最小化。求解 CSL 至少使用多少次魔法,能够达到最小化的目标。
输入描述:
第一行有一个整数 n,表示序列的长度。
接下来两行,每行有 n 个整数,分别表示初始序列 a 和 b。
输入数据保证每个序列里的数两两不同。
2≤n≤1e5
1≤ai,bi≤1e9
1≤ai,bi≤1e9
输出描述:
在一行输出一个整数,表示最少使用的魔法次数。
示例1
输入
2 1 2 1 2
输出
1
示例2
输入
2 1 2 2 1
输出
0
题意:两个数组,你每次可以交换任一个数组里两个元素的位置,求最小交换次数使a0b0+a1b1+…+an−1bn−1a0b0+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 }