codeforces 584 E. Anton and Ira(贪心,数组p经变换到数组s)

题目: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为止,其他的点也是。会发现,那样的话,每个点最终交换到目的地的过程中都没有走重复的路径,ans=\frac{1}{2}*\sum (p'[i]-i) (乘1/2是因为交换一次的cost,对两个点分别都产生了效果cost,总的产生了2*cost,即 2*ans=\sum (p'[i]-i) ,其中ans=\sum cost_{i}  )

交换步骤的输出,结合上面的分析就可以写出来了(详见代码)

#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);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值