2018CCPC网络赛A-Buy and Resell (补题)hdu6438

题目链接

题意是有n个城市,每个城市有一个物品的单价ai,商人需要依次遍历所有城市,并且在每个城市只能进行买、卖一个物品或啥也不干的操作,要求利润最大的情况及保证利润最大时的最小买卖次数。

解题思路:贪心。

最朴素的想法,当城市i的单价比后面的某个城市j单价低时,就可能通过买卖赚取一定的差价,而如果城市j的单价又比更后面的城市k低的话,那么在城市k卖赚取的差价要大。

我们可以依次枚举每个城市的单价,维护一个在当前城市之前的城市中单价从小到大的优先队列。
如果队列顶部的单价大于等于当前城市的值,很简单,直接将当前城市单价push入优先队列即可,因为在这个城市不会进行卖的操作;
否则,先pop队列顶部的单价,然后将之与当前城市的差价加到总利润上,分情况决定是否更新买卖次数,并且将当前城市的单价push进优先队列两次。
push两次是关键,前一次push是表面上在这里把当前队列顶部的物品在这里卖出去了,其实后面如果有更高的单价导致这个值pop时,不更新买卖次数,就相当于这个物品是在后面单价更大的城市出售的;后一次push是因为,如果出现了前一次的值被pop后,说明并没有在这个城市卖东西,那么是可能在这个城市买东西的。当然我们需要一个标记来区分是不是前一次那种情况,避免重复更新买卖次数。

此外,对于单价相同的城市,push两次的前一次优先级应该要比其他时候高,原因在于:
对于push两次的后一次push,必须前一次push的值出队列后才可以在这个城市购买物品;
对于小于等于队列顶部城市单价的值,优先卖前一次push的值可以使得获得同样利润时的买卖次数最少。

令高优先级为1,低优先级为2
举例:
4
3 1 3 4
初始时ans=0,cnt=0
将第一个城市的单价和优先级(3,2)加入队列                             队列:(3,2)                    ans=0,cnt=0
到第二个城市时单价为1小于队列顶部单价,直接将(1,2)加入队列             队列:(1,2)  (3,2)               ans=0,cnt=0
到第三个城市时单价大于队列顶部单价,且队列顶部优先级为2,说明是没有更新过买卖次数的,则ans+=(3-1),cnt+=2,将队列顶部元素pop,然后将(3,1),(3,2)加入队列                          队列:(3,1)  (3,2,)  (3,2)            ans=2,cnt=2
到第四个城市时单价大于队列顶部单价,且队列顶部优先级为1,说明是已经更新过买卖次数的,则ans+=(4-3),将队列顶部元素pop,然后将(4,1),(4,2)加入队列                                队列:(3,2)  (3,2)  (4,1)  (4,2)        ans=3,cnt=2

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define INF 0x3f3f3f3f
#define db double
#define ldb long double
#define m_p make_pair
#define p_b push_back
#define fbo friend bool operator <
const int N = 100010;
const int mod=1e9+7;
struct FastIO//输入挂
{
    static const int S=200;
    int wpos;
    char wbuf[S];
    FastIO():wpos(0){}
    inline int xchar()
    {
        static char buf[S];
        static int len=0,pos=0;
        if(pos==len) pos=0,len=fread(buf,1,S,stdin);
        if(pos==len) exit(0);
        return buf[pos++];
    }
    inline int read()
    {
        int s=1,c=xchar(),x=0;
        while(c<=32) c=xchar();
        if(c=='-') s=-1,c=xchar();
        for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0';
        return x*s;
    }
    ~FastIO()
    {
        if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0;
    }
}io;
int t,n,a[N];
struct node{
	int x,y;
	friend bool operator<(node a,node b){
		if(a.x==b.x) return a.y>b.y;
		return a.x>b.x;
	}
}q,p;
priority_queue<node> pq;
int main(){
	t=io.read();
	while(t--){
		while(!pq.empty()) pq.pop();
		n=io.read();
		For(i,1,n){
			a[i]=io.read();
		}
		ll ans=0;
		int cnt=0;
		q.x=a[1],q.y=2;
		pq.push(q);
		For(i,2,n){
			if(!pq.empty()){
				p=pq.top();
				if(a[i]<=p.x) q.x=a[i],q.y=2,pq.push(q);
				else{
					pq.pop();
					if(p.y==2) ans+=a[i]-p.x,cnt+=2;
					else ans+=a[i]-p.x;
					q.x=a[i],q.y=1,pq.push(q),q.y=2,pq.push(q);
				}
			}
		}
		printf("%lld %d\n",ans,cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38515845/article/details/82320963