2018CCPC网络赛1001:Buy and Resell(优先队列)

版权声明:谁他喵没事儿会转我的博客啊QAQ,有没有人看都是一回事儿。。。 https://blog.csdn.net/f2935552941/article/details/82055387

题目大意:

1到n每个城市有一个价值为a[i]的物品,当你到达这个城市的时候,可以花费a[i]买一个物品,也可以卖掉手中一个物品获得a[i],也可以什么都不做。问最后能够获得的最大利润是多少,最大利润相同时求最少的交易次数,同一时刻手中可以持有多个物品。

解题思路:

维护一个优先队列,每次到达一个城市,判断一下当前优先队列中最小的值是否小于当前城市的a[i],如果小于的话,就假设在这里将它卖掉,同时将这个城市的a[i]加入优先队列,注意这个时候需要加入两次,第一次是因为对于最小的我们可以选择不在这里交易而选择在后面某个城市交易,这样的话只是以这个城市为中转。第二次就是正常的将这个城市的物品加入优先队列。

这里注意题目需要我们计算最小次数,那么我们就可以往优先队列里面加入物品的时候打上标记,将二手的标记为1,卖出物品的时候价值相同时优先卖二手的即可。

Ac代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
typedef long long ll;
struct node
{
    int val,flag;   //flag为1标记为二手
    node(int val,int flag):val(val),flag(flag) {}
    bool operator<(const node &p) const
    {
        if(val==p.val) return flag<p.flag;  //价值相同 二手优先级高
        return val>p.val;
    }
};
int n,x;
ll res,ans;
priority_queue<node> que;
int main()
{
    int QAQ;
    scanf("%d",&QAQ);
    while(QAQ--)
    {
        res=0,ans=0;    //利润以及次数
        scanf("%d",&n);
        while(!que.empty()) que.pop();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(!que.empty())
            {
                node now=que.top();
                if(now.val<x)   //队列中最小的小于a[i]
                {
                    que.pop();res+=1LL*x-now.val;   //计算利润
                    if(now.flag==0) ans++;  //如果卖掉的是一手的 ans++
                    que.push(node(x,0));
                    que.push(node(x,1));
                }
                else que.push(node(x,0));
            }
            else que.push(node(x,0));
        }
        printf("%lld %lld\n",res,ans*2);
    }
}

猜你喜欢

转载自blog.csdn.net/f2935552941/article/details/82055387