题目链接
题意
有两个海盗,第一个海盗可以随便拿金币,第二个海盗每次都从剩下的金币里面拿第一个(太傻),然后问海盗a最多能拿多少个金币
解决
由于第一个人可以随便拿,那么不妨每次让其拿当前物品序列的第一个
开一个最小堆存下第一个人拿的所有物品的数量
如果这次对方拿的物品价值大于最小堆 中元素最小值,说明第一个人在之前某一轮不应该拿第一个,而是应该拿这次对方拿的这个物品
那么就把最小堆中最小元素删掉,把对方拿的这个物品加到set中表示拿这个物品,维护一个物品总价值即可
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <complex>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define E 1e-6
#define INF 0x3f3f3f3f
void open(){freopen("data.txt","r",stdin);}
void out(){freopen("out.txt","w",stdout);}
const int N = 101010;
const int MOD = 1e9 + 7;
/*
由于第一个人可以随便拿,那么不妨每次让其拿当前物品序列的第一个
开一个 最小堆 存下第一个人拿的所有物品的数量
如果这次对方拿的物品价值大于 最小堆 中元素最小值,说明第一个人在之前某一轮不应该拿第一个,而是应该拿这次对方拿的这个物品
那么就把set中最小元素删掉,把对方拿的这个物品加到set中表示拿这个物品,维护一个物品总价值即可
*/
int main()
{
//open();
priority_queue<int ,vector<int>,greater<int> > pq;
ll sum=0,tot=0; //Jack拿的物品总和,以及所有物品价值总和
int n,ans;
scanf("%d",&n);
bool turn=true; //turn为true表示该Jack船长取物品了
for(int i=0;i<n;i++)
{
scanf("%d",&ans);
tot+=ans;
if(turn) //该Jack取了
{
pq.push(ans);
sum+=ans;
}
else
{
if(ans>pq.top()) //Jack取了一个比较小的,这个比较小的应该留给另一个海盗,
{ //其实相当于Jack用之前的价值最小的那一个换了现在这个价值大的这个,一直换下去
sum-=pq.top();
pq.pop();
sum+=ans;
pq.push(ans);
}
}
turn=!turn;
}
//printf("%lld %lld",sum,tot-sum);
cout<<sum<<" "<<tot-sum<<endl;
}