1574 排列转换(鸽巢原理)

1574 排列转换

题目来源: CodeForces

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题

 

现在有两个长度为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 }
View Code

 

 

posted @ 2017-09-06 21:11  happy_codes  阅读(245)  评论(0编辑  收藏  举报