zoukankan      html  css  js  c++  java
  • 华农oj Problem J: 幻化【贪心/抽屉原理】

    Problem J: 幻化
    Time Limit: 2 Sec  Memory Limit: 128 MB
    Submit: 18  Solved: 3
    [Submit][Status][Web Board]
    Description
    遇见你是我一世的春暖花开,
    
    从此清风明月浩瀚星海。
    
    不论结局,很高兴认识你。
    
    她给了他一个长度为n的整数序列a[],他还给了她另外一个长度为n的整数序列b[],现在他想通过每次交换a[i],a[j]使序列a变成b,但是每次交换的代价是|j-i|。
    
    请问最少的代价是多少呢?(a序列和b序列均是[1,n]的一个全排列)
    
    Input
    第一行一个数字T代表测试的组数。(T<=10)
    
    对于每组测试第一行一个数字n表示序列的长度(1<=n<=2*10^5);
    
    接下来2行第一行n个数字a1,a2,a3...an (1<=ai<=n)
    
    第二行n个数字b1,b2,b3...bn(1<=bi<=n)
    
    Output
    对于每个测试输出一个整数,占一行,表示把a[]变成b[]所需要最少的交换代价。
    
    Sample Input
    2
    4
    1 2 3 4
    4 3 2 1
    4
    2 1 4 3
    1 2 3 4
    Sample Output
    4
    2 
    HINT
    
    对于第一组样例1 4交换,2 3交换,代价是4 
    
    
    第二组样例2 1交换,3 4交换,代价是2 
    
    题意:有两个长度为n的排列p和s。要求通过交换使得p变成s。交换 pi 和 pj 的代价是|i-j|。要求使用最少的代价让p变成s。
    
    考虑两个数字pi和pj,假如交换他们能使得pi到目标的距离减少,pj到目标的距离减少。那么应该交换他们,这是一个必要的操作,也是答案的下界。
    
    如果每一次都能找到这样的两个数字,那么答案就是排列p中的每个数字在排列s的位置的距离差之和/2.这显然是答案的下界。
    
    现在考虑证明这个下界是可以构造出来的。
    
    考虑排列p中最后一个位置不对的数字,不妨设为pj,他的目标位置是pi,那么如果p[i+1,j]中有任意一个数的目标是pk(k<i),那么可以进行必要交换。
    
    假设没有这样的一个数字使得他的目标是pk,一共有(j-i-1)个数,(j-i-2)个空,根据鸽巢原理,显然不存在这样的情况。
    
    也就是说,对于排列p中最后一个位置不对的数字pj,目标位置是pi,pi总能在p[i+1,j]中找到一个数字pk,使得它们交换之后到目标的距离都减小了。
    
    先将s映射成1-n的顺序排列,再将p根据同一映射函数映射成新的序列,得到新问题与原问题等价.
    
    现在我们要做的就是将pi移到i位置上,我们可以先从最小的pi开始移动,这样当我们移动任何一个pi时,假设pi当前位置为x,我们都能保证pi<=x,如果pi==x,那么移动结束,否则我们可以一直将pi向左交换,使得其越来月接近目标位置,在这个过程中,pi是不会产生更多代价的,但是和pi交换的元素有可能产生更多代价,因此我们每次必定要挑选pj>=x的pj去和pi交换,这样才能保证总代价不变大,可以证明[i,x-1]区间内一定存在pj>=x.(可以用抽屉原理证明)
     
    
    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    
    const int MAXN = 2e5+10;
    int a[MAXN];
    
    int main()
    {
        int n,x;
        long long ans=0;
        cin>>n;
        for(int i=0;i<n;++i){cin>>x;a[x]=i;}
        for(int i=0;i<n;++i){cin>>x;ans+=abs(a[x]-i);}
        cout<<ans/2<<endl;
    }
    
  • 相关阅读:
    论二级域名收集的各种姿势
    我喜欢你是寂静的-聂鲁达
    早晨充满-聂鲁达
    KALI Linux更新源
    lodash throttle和debounce
    lodash capitalize 首字母大写
    C# 格式化百分比
    c# PadLeft,PadRight用法
    对象名 XXX 无效。
    lambda 分组后的count
  • 原文地址:https://www.cnblogs.com/Roni-i/p/8996451.html
Copyright © 2011-2022 走看看