1574 排列转换(鸽巢原理)
现在有两个长度为n的排列p和s。要求通过交换使得p变成s。交换 pi 和 pj 的代价是|i-j|。要求使用最少的代价让p变成s。
Input
单组测试数据。 第一行有一个整数n (1≤n≤200000),表示排列的长度。 第二行有n个范围是1到n的整数,表示排列p。每个整数只出现一次。 第三行有n个范围是1到n的整数,表示排列s。每个整数只出现一次。
Output
输出一个整数,表示从排列p变到s最少要多少代价。
Input示例
样例输入1
4
4 2 1 3
3 2 4 1
Output示例
样例输出1
3
//假如每次能选出两个没归位的 i,j,位置的数,使他们交换后,i,j 离目标位置更近了,重复此操作,便是最小代价变动了。
证明必然存在这样的构造方式,
假如 i 位置的目标为 j 位置,那么 j -- n 位置中,必然有一个目标为 1 -- i 位置。
鸽巢原理,反证,先找到一组 i,j (i<j) ,且i,j位置之间的数都归位了,如果 i 目标位置为 j -- n ,那么必然 j -- n 有一个目标为 1 -- i ,交换 i ,j 即可。
这样的 i ,j 必定能找到一组,不可能每对 i,j (i<j)目标都为同一边!
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 #define LL long long 7 #define MOD 1000000007 8 #define N 200005 9 10 int n; 11 int p[N]; 12 int s[N]; 13 int pos[N]; 14 15 int main() 16 { 17 scanf("%d",&n); 18 for (int i=1;i<=n;i++) 19 { 20 scanf("%d",&p[i]); 21 pos[ p[i] ] = i; 22 } 23 24 for (int i=1;i<=n;i++) 25 scanf("%d",&s[i]); 26 27 LL ans = 0; 28 for (int i=1;i<=n;i++) 29 { 30 int x = pos[s[i]]; 31 ans=ans+abs(x-i); 32 } 33 printf("%lld\n",ans/2); 34 35 return 0; 36 }