2013年NOIP提高组 火柴排队

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:

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

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

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

根据距离的定义,最小的距离应该是数列a的第 i 大数 与数列b的第 i 大数分别做差,离散化后就变成了 ai 与 bi 相等,即求数列 a 基于 数列 b 的逆序对个数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int size = 100010;
int num[size];
int templ[size];
int temp[size];
int ans = 0;
int n;
int a[size],b[size];
int cmp[size];
const int mod = 99999997;
int EF(int l,int r,int k,int *tmp)
{
    while(r - l > 1)
    {
        int mid = (l + r) >> 1;
        if(tmp[k] > templ[mid])
            l = mid;
        else if (tmp[k] < templ[mid])
            r = mid;
        else
            return mid;
    }
    return r;
}
void lsha()
{
    for(int i = 1 ; i <= n ; i ++)
        templ[i] = a[i];
    sort( templ+1 , templ+n+1 );
    for(int i = 1 ; i <= n ; i ++)
        a[i] = EF(0,n+1,i,a);
}
void lshb()
{
    for(int i = 1 ; i <= n ; i ++)
        templ[i] = b[i];
    sort( templ+1 , templ+n+1 );
    for(int i = 1 ; i <= n ; i ++)
        b[i] = EF(0,n+1,i,b);
}
void merge(int l,int r)
{
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    merge(l,mid) , merge(mid+1,r);
    int ll = l , rr = mid + 1 , p = ll;
    while(ll <= mid || rr <= r)
    {
        if(rr > r || (ll <= mid && cmp[a[ll]] <= cmp[a[rr]]))
            temp[p++] = a[ll++];
        else
        {
            temp[p++] = a[rr++];
            ans += mid - ll + 1;
            ans %= mod;
        }
    }
    for(int i = l ; i <= r ; i ++)
        a[i] = temp[i];
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d",&a[i]);
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d",&b[i]);
    lsha();
    memset(templ,0,sizeof(templ));
    lshb();
    for(int i = 1 ; i <= n ; i ++)
        cmp[b[i]] = i;
    merge(1,n);
    printf("%d",ans%mod);
    return 0;
}

传送门 :
codevs 3286
tyvj 2515

你可能感兴趣的:(逆序对)