题目:http://codeforces.com/contest/584/problem/E
题意:有两个数组p,s,长度为n,且是1~n的排列。要使数组p变为s,每交换 i 和 j 两个位子上的数,花费为 | i - j | (i和j表示的是位子的编号,而不是该位子上的数的值),求最小花费,并输出交换的步骤。
思路:先将s映射成1~n的顺序排列,,即 pos[ s[ i ] ] = i,再将p根据同一映射函数映射成新的序列(详见代码)
对于那些不在自己位子上(即需要交换)的数,从小到大去选数移动,直到移到其该到的位子为止。想一下会发现,假设现移动当前最小数a,现在所在的位置是b,应该去到最小位置a,该数a必定是需要去往左交换的,而b左侧必定至少有一个数c是需要交换到>=b的位置的(若拿其他数x往右交换到位置b,可能会超过其应该去的位置x,而之后还需要将x往左交换回去,会出现重复的花费),那么就拿a和c交换,a往左边的目的地a位置靠,c往右边的目的地c位置靠,对于两者来说都是在走前往目的地的单程路径,并没有走重复的路。第一次交换后,若a仍没到位置a,那么接下去的情况都和前面情况的解决方法是相同的,继续找目的地位置在a当前位置now右侧的点进行交换,直至a交换到位置a为止,其他的点也是。会发现,那样的话,每个点最终交换到目的地的过程中都没有走重复的路径, (乘1/2是因为交换一次的cost,对两个点分别都产生了效果cost,总的产生了2*cost,即
,其中
)
交换步骤的输出,结合上面的分析就可以写出来了(详见代码)
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <functional>
#include <algorithm>
#include <bitset>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstddef>
#include <memory>
#include <vector>
#include <cctype>
#include <string>
#include <cmath>
#include <queue>
#include <deque>
#include <list>
#include <ctime>
#include <stack>
#include <sstream>
#include <map>
#include <set>
//#include <unordered_map>
//#include <unordered_set>
//#pragma GCC optimize(3)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pb push_back
#define mkp(a,b) make_pair(a,b)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define fi first
#define se second
#define lc (d<<1) //d*2
#define rc (d<<1|1) //d*2+1
#define eps 1e-9
#define dbg(x) cerr << #x << " = " << x << "\n";
#define mst(a,val) memset(a,val,sizeof(a))
#define stn(a) setprecision(a)//小数总有效位数
#define stfl setiosflags(ios::fixed)//点后位数:cout<<stfl<<stn(a);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI=3.1415926535897932;
const int MAXN=1e5+10;
const ll mod=1e9+7;
ll inline mpow(ll a,ll b){ll ans=1;a%=mod;while(b){if(b&1)ans=(ans*a)%mod;a=(a*a)%mod,b>>=1;}return ans;}
int inline sgn(double x){return (x>-eps)-(x<eps);} //a<b:sgn(a-b)<0
priority_queue<int,vector<int>,greater<int> > qu; //up
priority_queue<int,vector<int>,less<int> > qd; //dn
const int inf = 0x3f3f3f3f; //9
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
int n;
int p[2010],s[2010];
int pos[2010];
int ans;
vector<PII>vec;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) {scanf("%d",&s[i]);pos[s[i]]=i;}
for(int i=1;i<=n;i++) p[i]=pos[p[i]];
for(int i=1;i<=n;i++) ans+=abs(i-p[i]);
ans/=2;
for(int i=1;i<=n;i++)
{
int now;
for(int j=1;j<=n;j++)
if(p[j]==i) now=j;
if(now!=i)
for(int j=now;j>=i;j--)
if(p[j]>=now)
{
swap(p[now],p[j]);
vec.pb(mkp(now,j));
now=j;
}
}
printf("%d\n",ans);
printf("%d\n",vec.size());
for(int i=0;i<vec.size();i++)
printf("%d %d\n",vec[i].fi,vec[i].se);
}