NOIP 2013 提高组 day1 T2 火柴排队 归并 逆序对

描述

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:i=1n(aibi)2∑i=1n(ai−bi)2,其中 aiai 表示第一列火柴中第 i 个火柴的高度,bibi 表示第二列火柴中第 i 个火柴的高度。

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

格式

输入格式

共三行,第一行包含一个整数 n,表示每盒中火柴的数目。

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

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

输出格式

输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果

样例1

样例输入1[复制]

 4
2 3 1 4
3 2 1 4

样例输出1[复制]

 1

样例2

样例输入2[复制]

4

1 3 4 2

1 7 2 4

样例输出2[复制]

2

解题报告

刚拿到这道题的时候有一点懵,好吧可能自己现在能力不够。

这道题先快排得到两个对应序列是距离最小的(这点是想到了的),记录第二组的位置排序,然后将第一组序列按原位置排列同时将对应的那一组序列排好序,以这组的位置序列为归并序列求逆序对。(好像有点乱,下面来讲解)

a.data:1 3 4 2   a.pos:1 2 3 4 

b.data:1 7 2 4  b.pos:1 2 3 4

排序(a,b,data)后

a.data:1 2 3 4 a.pos:1 4 2 3

b.data:1 2 4 7 b.pos:1 3 4 2

记录对应a.ca: 1 3 4 2

排序(a,pos)后

data=a.ca:1 4 2 3

然后归并 求逆序对

代码附下

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mm=99999997;
int    n,data[100005],ans,y[100005]; 
struct pp{
    int data,pos,ca;
};
pp a[100005],b[100005];
int comp(const pp&a,const pp&b)
{
    return a.data<=b.data;
}
int comp2(const pp&a,const pp&b)
{
    return a.pos<=b.pos;
}
void mergesort(int l,int r)
{
    if (l==r) return ;
    int mid=(l+r)>>1;
    mergesort(l,mid);
    mergesort(mid+1,r);
    int i=l;
    int j=mid+1;
    int o=l;
    while (i<=mid||j<=r)
    {
        if (j>r||i<=mid&&data[i]<=data[j])
            y[o++]=data[i++];
        else
        {
            y[o++]=data[j++];
            ans=(ans+mid-i+1)%mm;//WA ans+=(mid-i+1)%mm 
        }
    }
    while(i<=mid)
          y[o++]=data[i++];
    while (j<=r)
      y[o++]=data[j++];
    for (int i=l;i<=r;i++)
      data[i]=y[i];
}
int main()
{
    freopen("match.in","r",stdin);
    freopen("match.out","w",stdout);
    cin>>n;
    for (int i=1;i<=n;i++)
      {
          scanf("%d",&a[i].data);
          a[i].pos=i;
      }
    for (int i=1;i<=n;i++)
      {
          scanf("%d",&b[i].data);
          b[i].pos=i;
      }
    sort(a+1,a+1+n,comp);
    sort(b+1,b+1+n,comp);
    for (int i=1;i<=n;i++)
        a[i].ca=b[i].pos;
    sort(a+1,a+1+n,comp2);
    for (int i=1;i<=n;i++)
       data[i]=a[i].ca;
    mergesort(1,n);
    cout<<ans;
    return 0;
}
啊,对,要注意  ans+=(mid-i+1)%mm   ans=(ans+mid-i+1)%mm; 的区别
前者要错最后两组数据 后者不会
 
多复习复习归并排序
 
好像还可以用树状数组,还有冒泡排序;
如果有时间再写。
原文地址:https://www.cnblogs.com/lx0319/p/5661731.html