NOIP 2013 火柴排队

洛谷 P1966 火柴排队

洛谷传送门

JDOJ 2227: [NOIP2013]火柴排队 D1 T2

JDOJ传送门

Description

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

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

Input

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

Output

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

Sample Input

Sample Input I: 4 2 3 1 4 3 2 1 4 Sample Input II: 4 1 3 4 2 1 7 2 4

Sample Output

Sample Output I: 1 Sample Output II: 2

HINT

【样例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 ≤ 1,000;

对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ 231 − 1。

Source

NOIP2013提高组

题解:

这是一道求逆序对的题目;

求逆序对的手段有的时候是次要的,我们首先要弄明白为什么这道题是求逆序对的题。

那么让我来概括一下题目大意:

让你把两列火柴排一下队,使得俩队列中序号相同的两根火柴的高度差值最小。

然鹅,最终要求的竟然不是最小差值,而是差值最终需要交换多少次//%%%

所以我们得出这个结论,这两列火柴必须是最大匹配最大,次大匹配次大,以此类推,才能得出最小差值。

再看看题目中要求只能交换相邻的两个火柴的位置,所以我们想到了求逆序对个数。

那么我们开始回头看逆序对咋求。

1、归并排序

2、树状数组

3、暴力(想到这种方法的当场打死)

都挺简单的,因为我是在树状数组板块中学的逆序对,所以我使用了树状数组求逆序对。

如果通过逆序对本身的定义来理解的话,我们会发现:这个逆序对不应该用树状数组求啊?但是人类的智力是无极限的,我们回顾一下树状数组的用途,发现这个玩意是用来区间求和的,也就是说,这个东西只能裸的求和?

那未免太辱没它的名头了。

我们这样想,树状数组在求逆序对的时候只是一个求和的工具,我们可以通过树状数组来求当前这个数所在位置前面比它大的数的个数,就可以方便的统计逆序对的个数。

所以我们考虑把每个火柴定义一个结构体,一个存编号,也就是位置,一个存长度。最后我们按照长度由小到大排序(当然由大到小也可以),最后我们进行整个程序也是思路中最重要的点:离散化

简单介绍一下离散化。这算是一种常用的小技巧,适用于什么情况呢?就是我们在解题过程中只在意这个数的大小关系,而不在意这个数到底是多大。我们可以形象地理解一下,现在有5个数分布在1-10000000的区间内,我们只需要知道他们到底多大,所以我们建一个离散化数组D[],其中D[i]表示第i个元素在其中排第j位,这个j最大也只是5.

这个过程就叫做离散化。

显然这道题适用离散化。

所以我们将数据离散化之后,就可以进行树状数组的处理,其中树状数组函数getsum(sum[i])就表示比高度为i的元素大的数的个数。

然后统计ans的时候要记得ans+=i-getsum(sum[i]);表示当前位置减去比当前位置大的所有元素的个数。

注意每次操作的时候都取模。

AC code:

#include<cstdio>
#include<algorithm>
#define mod 99999997
using namespace std;
struct node
{
    int h,order;
}a[100010],b[100010];
int c[100010],sum[100010],n,ans;
bool cmp(node a,node b)
{
    return a.h<b.h;
}
void fix(int x)
{
    for(int i=x;i<=n;i+=i&-i)
        c[i]++,c[i]%=mod;
}
int getsum(int x)
{
    int ret=0;
    for(int i=x;i;i-=i&-i)
        ret+=c[i],ret%=mod;
    return ret;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].h);
        a[i].order=i;
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i].h);
        b[i].order=i;
    }
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=n;i++)
        sum[a[i].order]=b[i].order;
    for(int i=1;i<=n;i++)
    {
        fix(sum[i]);
        ans+=i-getsum(sum[i]);
        ans%=mod;
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11281980.html