码迷,mamicode.com
首页 > 其他好文 > 详细

NOIP2013火柴排队

时间:2015-09-14 22:30:26      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

咱家今天作业有点多,就刷了一道,不开森

题目简述:给你两个长度为n的序列,你可以每次交换其中一个序列中两个数的位置,问你最少需要多少次交换是两序列的对应项的差的和最小

我都把题目简化成这样了,就应该很明显了吧,假设我们把两个序列都sort掉此时的和是最小的,至于为什么,看下面:

   (1)设序列只有两个数分别是a,b;c,d;且c < d,a < b

令S1=(a-c)(a-d)+(b-d)(b-d),S2=(a-d)(a-d)+(c-b)(c-b),则:

S1-S2=2ad+2bc-2ac-2bd=2a(d-c)+2b(c-d)=2(d-c)(a-b)。由已知条件易知S1 < S2。

   (2)由数学归纳法可以知道假设k个都是按序拍距离最小,第K+1项也一定是满足这样的顺序才能保证最小。

我们在struct中存下它的值已经原来的位置,sort a,b ,即目标状态,再用rank记录下对应点的关系,然后就是BIT+逆序对啦

那么问题就简化到了模板上,不要问我逆序对是什么,自己去百度吧

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;

typedef long long ll;

const int mod = 1e8 - 3;
const int Size = 1e5 + 5;

struct data{
    int v,num;
};

int n,ans;
int bit[Size],rank[Size];
data a[Size],b[Size];

bool cmp(data,data);void updata(int);
int ask(int);

int main(){
    scanf("%d",&n);
    for (int i = 1;i <= n; ++i)
        scanf("%d",&a[i].v);
    for (int i = 1;i <= n; ++i)
        scanf("%d",&b[i].v);
    for (int i = 1;i <= n; ++i)
        a[i].num = b[i].num = i;
    sort(a + 1,a + n + 1,cmp);
    sort(b + 1,b + n + 1,cmp);
    for (int i = 1;i <= n; ++i)
        rank[a[i].num] = b[i].num;for (int i = 1;i <= n; ++i){
        updata(rank[i]);
        ans = (ans + i - ask(rank[i])) % mod;
    }
    printf("%d\n",ans);
    return 0;
}

bool cmp(data a,data b){
    return a.v < b.v;
}void updata(int x){
    for (int i = x;i <= n; i += i & -i)
        ++bit[i];
}

int ask(int x){
    int ans = 0;
    for (int i = x;i; i -= i & -i)
        ans += bit[i];
    return ans;
}

 

NOIP2013火柴排队

标签:

原文地址:http://www.cnblogs.com/GENEVE/p/4808318.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!