P1966 火柴排队

P1966 火柴排队

题目描述
涵涵有两盒火柴,每盒装有 nn 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ¥\(\sum (a_i-b_i)^2∑(a i ​ −b i ​ ) 2\)

其中 a_i

​ 表示第一列火柴中第 i 个火柴的高度, b_i

​ 表示第二列火柴中第 i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

输入输出格式
输入格式:
共三行,第一行包含一个整数 nn ,表示每盒中火柴的数目。

第二行有 n n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 nn 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式:
一个整数,表示最少交换次数对 99,999,99799,999,997 取模的结果。


很经典的一道题, 以前就做过了, 今天培训讲到, 写博客复习一下

首先我们可以 瞎j8猜 判断出: 当两个火柴序列在本序列内排序同另一个序列相同, 则答案最优。 什么意思呢?就是当在第一个序列中, 排名为 \(x\) 的火柴棒排在第 \(p\) 个, 而在第二个序列中排名为 \(x\) 的火柴棒也排在第 \(p\) 个, 当每一个火柴棒满足这一条件时, 得出的和最小, 显然转化为逆序对的求解问题。

在一般的逆序对问题中, 通常只给出一个序列, 直接求逆序对的个数。 但是事实上, 这不是等价于给你两个序列, 一个无序, 另一个有序 \(1, 2, 3, 4..., n\) 求解将第一个排序成为有序的那个的逆序对个数吗? 换句话说, 本题也是求解逆序对, 只是已经给出排序的依据(可以A为依据排序B, 亦可以以B为依据排序A), 而不是普通的有序序列。

所以我们先对\(A,B\)按照值的大小排序, 以有序序列为桥梁, 找出 \(A,B\) 的对应关系(这个过程中可以离散化一下), 再(按照 \(A\) 的原始顺序)排序回来, 就得到了(以 \(A\) 为依据)的 \(B\) 的排序顺序了

树状数组求解逆序对即可

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define lowbit(i) ((i) & (-i))
typedef long long LL;
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 10000019,M = 99999997;
LL num;
LL c[maxn];
void update(LL x,LL val){for(LL i = x;i < maxn;i += lowbit(i))c[i] += val;}
LL getsum(LL x){
    LL ans = 0;
    for(LL i = x;i > 0;i -= lowbit(i))ans += c[i];
    return ans;
    }
struct A{
    LL val,index;
    }a[maxn],b[maxn],I[maxn];
bool cmp1(A a,A b){return a.val < b.val;}
bool cmp2(A a,A b){return a.index > b.index;}
int main(){
    num = RD();
    for(LL i = 1;i <= num;i++)a[i].val = RD(),a[i].index = i;
    for(LL i = 1;i <= num;i++)b[i].val = RD(),b[i].index = i;
    sort(a + 1,a + 1 + num,cmp1);
    sort(b + 1,b + 1 + num,cmp1);
    for(LL i = 1;i <= num;i++)I[i].val = a[i].index,I[i].index = b[i].index;
    sort(I + 1,I + 1 + num,cmp2);
    LL ans = 0;
    for(LL i = 1;i <= num;i++){
        update(I[i].val,1);
        ans += getsum(I[i].val - 1);
        ans %= M;
        }
    printf("%lld\n",ans);
    return 0;
    }
posted @ 2018-07-17 15:13  Tony_Double_Sky  阅读(226)  评论(0编辑  收藏  举报