GYM 100488 Two Pirates(想法)

来源:互联网 发布:淘宝怎么找不到高仿表 编辑:程序博客网 时间:2024/06/09 23:09

题目链接

题意

有两个海盗,第一个海盗可以随便拿金币,第二个海盗每次都从剩下的金币里面拿第一个(太傻),然后问海盗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 0x3f3f3f3fvoid 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;}
原创粉丝点击