HDU-6438丨优先队列

这题看起很简单,但是想法不好,代码就会又臭又长,想法好代码就很香了(x)
题意:依次经过n个城市,每个城市有物价ai,在每个城市只能买一、卖一或者什么都不做,求在买卖商品的最大毛利和最少交易次数(买卖都算一次交易),假设金钱无限。

思路:
1.首先假设手头有一些商品,来到一个物价更高的城市,为了最大毛利,肯定会把最便宜的i在此城市以aj的价格卖掉,获利aj-ai,交易次数是i买j卖。每次都是对最便宜的操作。

2.如果下一次来到了城市k,且ak>aj(也就是先前卖掉i物品的地方),那我们本应该把i在k卖掉更优,现在怎么办呢?其实这不影响我们计算答案,因为只要收益加上ak-aj即可,因为容易想到,ak-ai=(ak-aj)+(aj-ai)。那么交易次数呢?原先i~j的交易是两次,如果i~k交易那也是两次,也就是说“反悔”是不增加交易次数的。

3.根据2的发现,可知计算答案与具体哪个物品在哪交易没有直接关联,我们只需要知道曾经卖出的城市,是否被反悔。如果被反悔的话,为了最大化收益,我们都假设不卖就买(但不计数)。如果没有反悔,每次卖出,cnt+2,ans+差值。如果时因为反悔而选择的新的卖出地,cnt不变,ans+与上个卖出地的差值。

4.根据上面的分析,我们需要一个数据结构,遍历所有的地区,每次拿出最便宜的“商品”或者“卖出地”进行比较,
 如果当前地区物价不高于拿出的“商品”或者“卖出地”,那么没有收益,“商品”的形式存入结构。
 如果高于,那么可以有收益,取出这个“商品”或者“卖出地”,
  ans都加上差值,
   若是商品则cnt+2,
   若是卖出地则cnt不变,但是需要存入上个出卖地的商品,体现不卖则买。
  把当前卖出地存入结构。

5.讲到这里完全可以用结构体+优先队列小顶堆来做啦!结构体需要重载一下小于号,存入v和id,分别表示这个“商品”或者“卖出地”的价值,和上次出卖的地方(没有就记为inf,优先更新卖出地,使得交易次数最少)。稍微处理一下应该很好做。下面这份代码给出了更加“偷懒”的写法,用pair打标记,first是价值,second标签1是出卖地,标签2是商品,每次交易都把出卖地和商品都压入,由于排序的原因,出卖地总会在前面,那么如果出卖地被更新了,商品就会在排序中浮上来了。消耗空间多一点,但是非常轻松。
(typedef似乎快一些?)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;

int main( )
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        ll ans=0,cnt=0;
        priority_queue<pll,vector<pll>,greater<pll> >q;
        scanf("%d",&n);
        for(int v,i=1;i<=n;i++)
        {
            scanf("%d",&v);
            if(!q.empty()&&q.top().first<v){
                cnt++;
                pll t=q.top();q.pop();
                if(t.second==1)cnt--;
                else cnt++;
                ans+=v-t.first;
                q.push({v,1});
                q.push({v,2});
            }else{
                q.push({v,2});
            }
        }
        printf("%lld %lld\n",ans,cnt);
    }
    return 0;
}

/*
5
5
1 2 3 4 5
5
2 2 9 9 2
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值