P1092 - 【NOIP2013】火柴排队 解题报告

P1092 - 【NOIP2013】火柴排队

Description

这里写图片描述

Input

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

Output

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

Sample Input

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

Sample Output

样例输出1:
1
样例输出2:
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 ≤火柴高度≤ 2^31 − 1。

solution

对于此题,很容易证明火柴的位置就是把两列的火柴都排序一下的位置。然后求火柴最少的交换次数(而且是相邻的),所以就是求逆序对,用归并或者树状数组求就行了。

代码如下:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define INF 0x7ffffff
#define clear(s,z) memset(s,z,sizeof(s))
#define copy(s,z) memcpy(s,z,sizeof(s))
#define mod 99999997
const int maxn=1e5+20;

struct dsl{
    int v,mark;
};

int n;
dsl a[maxn],b[maxn],c[maxn];
int tmp[maxn],ans;
int read()
{
    char ch;
    do{ch=getchar();
    }while(ch>'9' || ch<'0');
    int sum=0;
    do{
        sum=sum*10+ch-48;
        ch=getchar();
    }while(ch>='0'&& ch<='9');
    return sum;
}

bool cmp_(const dsl &a,const dsl &b)
{
    return a.v<b.v;
}

void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)a[i].v=read(),a[i].mark=i;
    for(int i=1;i<=n;i++)b[i].v=read(),b[i].mark=i;
    sort(a+1,a+n+1,cmp_);
    sort(b+1,b+n+1,cmp_);
    for(int i=1;i<=n;i++)
        c[i].v=a[i].mark,c[i].mark=b[i].mark;
    sort(c+1,c+n+1,cmp_);
}

void Merge(int l,int m,int r)
{
    int i=l,j=m+1,k=l;
    while(i<=m && j<=r)
    {
        if(c[i].mark>c[j].mark)
        {
            tmp[k++]=c[j++].mark;
            ans=(ans+m-i+1)%mod;
        }else
        {
            tmp[k++]=c[i++].mark;
        }
    }
    while(i<=m)tmp[k++]=c[i++].mark;
    while(j<=r)tmp[k++]=c[j++].mark;
    for(int i=l;i<=r;i++)
        c[i].mark=tmp[i];
}

void Merge_sort(int l,int r)
{
    if(l<r)
    {
        int mid=(l+r)/2;
        Merge_sort(l,mid);
        Merge_sort(mid+1,r);
        Merge(l,mid,r);
    }
}

void doing()
{
    Merge_sort(1,n);
    printf("%d\n",ans);
}

int main()
{
    init();
    doing();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值