火柴排队

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

其中 a_ia
i
​ 表示第一列火柴中第 i i个火柴的高度,b_ib
i
​ 表示第二列火柴中第 ii 个火柴的高度。

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

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

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

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

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

输入输出样例
输入样例#1:
4
2 3 1 4
3 2 1 4
输出样例#1:
1
输入样例#2:
4
1 3 4 2
1 7 2 4
输出样例#2:
2

思路

  1. 可以发现,要满足条件,即要使两列火柴小对小,大对大
  2. 让ab数组由小到大排列,同时保存id
  3. 我们令 q[a[i]] = b[i],相当于以 a[i] 为关键字对序列b[i] 排序。
  4. 若序列a 与序列 b 相等,那么此时 q[a[i]] 应该等于 a[i]的,也就是 q[i] = i
  5. 那么也就是说如果我们想让序列 a 与序列 b 相等,那么我们需要让 q 升序排列
  6. 问题就变为,将原本乱的 q 序列升序排列的最少交换次数
  7. (代码中q数组为a1)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define mod 99999997
#define N 100005
struct matches{
    int v,id;
}a[N],b[N];
int n,id;
int a1[N],b1[N];
long long ans;

bool Cmp(const matches a,const matches b){
    if(a.v==b.v) return a.id<b.id;
    return a.v<b.v;
}

void merge(int l,int m,int r){
    int i=l,k=l,j=m+1;
    while(i<=m && j<=r)
        if(a1[i]<=a1[j]) b1[k++] = a1[i++];
            else ans += m-i+1,ans%=mod,b1[k++] = a1[j++];
    while(i <= m) b1[k++] = a1[i++];
    while(j <= r) b1[k++] = a1[j++];
    for(int i=l; i<=r; i++) a1[i] = b1[i];
}

void merge_sort(int l,int r){
    if(l == r) return;
    int m = (l+r)>>1;
    merge_sort(l,m);
    merge_sort(m+1,r);
    merge(l,m,r);
}

int main()
{
//	freopen("match.in","r",stdin);
//	freopen("match.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<=n; i++){
        scanf("%d",&a[i].v);
        a[i].id = i;
    }
    for(int i=1; i<=n; i++){
        scanf("%d",&b[i].v);
        b[i].id = i;
    }
    sort(a+1,a+1+n,Cmp);
    sort(b+1,b+1+n,Cmp);
    for(int i=1; i<=n; i++)
        a1[b[i].id] = a[i].id;
    //求逆序
    merge_sort(1,n);
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值