原题链接http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2211
比赛描述
MiaoMiao和Bird经常在一起玩游戏,为了不让MiaoMiao玩腻,Bird经常发明一些新颖的游戏。
有一天,Bird发明一种抽卡片游戏,首先Bird在桌面上放N张卡片,按照1,2,...,N编号。每张的正面都有一个正整数ai,反面有一个正整数bi。
如果Bird抽到了某个卡片,他将得到ai分数。反之,如果MiaoMiao抽到了某张卡片,她将得到bi分数。
Bird和MiaoMiao都知道这N张卡片正反面的数字,游戏由Bird开始轮流抽取卡片,抽到的卡片不能够再次被抽取,游戏进行到所有卡片抽完结束。
贪心的MiaoMiao使用非常简单的策略:每次在剩下的卡片中选择bi最大的那个。bi相同的情况下选择编号i比较小的。
机智的Bird则有更加长远的眼光:由于他非常离了解MiaoMiao,所以他在知道MiaoMiao的策略选择下,会采取最优策略,最大化他的最终分数减去MiaoMiao最终分数的差。
对于给出的条件,请你帮Bird计算出Bird的最终分数减去MiaoMiao的最终分数。
输入
第一行表示一个正整数N(1 ≤ N ≤ 105),表示卡片的个数。 第二行N个正整数ai,表示Bird抽取第i张卡片的分数。 第三行N个正整数bi,表示MiaoMiao抽取第i张卡片的分数。 (1 ≤ ai, bi ≤ 10^9)
输出
输出一个整数,表示Bird的最终分数减去MiaoMiao最终分数的差。
样例输入
5
1 2 3 4 5
5 1 2 4 3
样例输出
4
以5个物品为例,按照MiaoMiao选择优先度排序,为0,1,2,3,4号物品
Bird所有选择方式中下标最小的方式是选择第0,2,4号物品
Bird其他选择方式可以视作由下标最小的方式中把一部分下标小的物品替换为下标大的物品得到
例如选择方式2,3,4可以视作0,2,4把0号物品替换为3号物品得到
那么剩下问题是如何替换。
如果有物品1和物品2,其中a1+b1>a2+b2且Bird只能选择一个
那么Bird选择物品1,差为a1-b2,选择物品2,差为a2-b1
因为(a1-b2)-(a2-b1)>0,所以选择物品1收益大
易证Bird应当尽可能多的选择a+b比较大的物品。
认为一开始选择的物品是0,2,4,只能把下标较小的物品替换为下标较大的
从前往后扫一遍排好序的物品,设下标index。
当index%2==0时,视作选择这个物品,将其压入优先权队列
当index%2==1时,将该物品a+b值与之前已经选择的物品中a+b值最小的比较,如果该物品a+b值大,将其替换进优先权队列,表示将一个已经选择的物品中a+b值最小的替换为该物品。
扫完最后结果也就出来了,复杂度O(nlogn)
代码
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
using namespace std;
int N;
struct ab
{
int a;
int b;
int sum;
};
ab cards[100000];
int index[100000];
bool cmp(int a,int b)
{
return (cards[a].b>cards[b].b)||(cards[a].b==cards[b].b&&a<b);
}
bool operator>(ab a,ab b)
{
return a.sum>b.sum;
}
bool operator<(ab a,ab b)
{
return a.sum<b.sum;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&(cards[i].a));
for(int i=0;i<N;i++)
{
scanf("%d",&(cards[i].b));
cards[i].sum=cards[i].a+cards[i].b;
index[i]=i;
}
sort(index,index+N,cmp);
priority_queue <ab,vector<ab>,greater<ab> > pq;
long long int ans=0;
for(int i=0;i<N;i++)
{
if(i%2==0)
{
pq.push(cards[index[i]]);
ans+=cards[index[i]].a;
}
else
{
ab top=pq.top();
if(cards[index[i]].sum>top.sum)
{
pq.pop();
pq.push(cards[index[i]]);
ans+=cards[index[i]].a-top.sum;
}
else
{
ans-=cards[index[i]].b;
}
}
}
printf("%I64d\n",ans);
return 0;
}