火柴排队

【题目描述】
涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:
,其中ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第i个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对99999997取模的结果。

【输入描述】
共三行,第一行包含一个整数n,表示每盒中火柴的数目。
第二行有n个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有n个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

【输出描述】
输出共一行,包含一个整数,表示最少交换次数对99999997取模的结果。

【样例输入】

样例1:
4
2 3 1 4
3 2 1 4

样例2:
4
1 3 4 2
1 7 2 4

【样例输出】

样例1:
1

样例2:
2

【数据范围及提示】

样例1说明:最小距离是0,最少需要交换1次,比如:交换第1列的前2根火柴或者交换第2列的前2根火柴。

样例2说明:最小距离是10,最少需要交换2次,比如:交换第1列的中间2根火柴的位置,再交换第2列中后2根火柴的位置。

对于10%的数据,1 ≤ n ≤ 10; 

对于30%的数据,1 ≤ n ≤ 100; 

对于60%的数据,1 ≤ n ≤ 1000; 

对于100%的数据,1 ≤ n ≤ 100000,0 ≤ 火柴高度 ≤ 2^31-1。

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct Node
{
    int Sum,Num;
};
Node i1[100001],i2[100001];
int n,ans(0),i[100001],h[100001];
bool Rule(Node t1,Node t2)
{
    return t1.Sum>t2.Sum;
}
void Merge(int t1,int t2) //归并排序求逆序对。
{
    if (t1==t2)
      return;
    int t=(t1+t2)>>1,x=t1,y=t+1,num=t1;
    Merge(x,t);
    Merge(y,t2);
    while (x<=t&&y<=t2)
      if (i[x]>i[y])
      {
          ans=(ans+t-x+1)%99999997; //凡事都要多动脑子,回溯上来啦,两段早就排好啦。
          h[num++]=i[y++];
      }
      else
        h[num++]=i[x++];
    while (x<=t)
      h[num++]=i[x++];
    while (y<=t2)
      h[num++]=i[y++];
    for (int a=t1;a<=t2;a++)
      i[a]=h[a];
}
int main() //恶心的预处理。
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
    {
          scanf("%d",&i1[a].Sum);
          i1[a].Num=a;
    }
    for (int a=1;a<=n;a++)
    {
          scanf("%d",&i2[a].Sum);
          i2[a].Num=a;
    }
    sort(i1+1,i1+n+1,Rule);
    sort(i2+1,i2+n+1,Rule);
    for (int a=1;a<=n;a++) //杀死脑细胞。
      i[i2[a].Num]=i1[a].Num;
    Merge(1,n);
    printf("%d",ans);
    return 0;
}

/*
    举个例子:
        5
        3 2 1 4 5
        5 2 1 4 3
    那么在第二个序列中就有:
        5应当排第5个;
        2应当排第2个;
        1应当排第3个;
        4应当排第4个;
        3应当排第1个;
    排完序不就是解吗?问题转化为求52341的逆序对,共7步。
*/
原文地址:https://www.cnblogs.com/Ackermann/p/5401498.html