Buy and Resell HDU - 6438(补)更新贪心

5 篇文章 0 订阅
4 篇文章 1 订阅

The Power Cube is used as a stash of Exotic Power. There are nn cities numbered 1,2,…,n1,2,…,n where allowed to trade it. The trading price of the Power Cube in the ii-th city is aiai dollars per cube. Noswal is a foxy businessman and wants to quietly make a fortune by buying and reselling Power Cubes. To avoid being discovered by the police, Noswal will go to the ii-th city and choose exactly one of the following three options on the ii-th day:

  1. spend aiai dollars to buy a Power Cube
  2. resell a Power Cube and get aiai dollars if he has at least one Power Cube
  3. do nothing

Obviously, Noswal can own more than one Power Cubes at the same time. After going to the nn cities, he will go back home and stay away from the cops. He wants to know the maximum profit he can earn. In the meanwhile, to lower the risks, he wants to minimize the times of trading (include buy and sell) to get the maximum profit. Noswal is a foxy and successful businessman so you can assume that he has infinity money at the beginning.

Input

There are multiple test cases. The first line of input contains a positive integer TT (T≤250T≤250), indicating the number of test cases. For each test case:
The first line has an integer nn. (1≤n≤1051≤n≤105)
The second line has nn integers a1,a2,…,ana1,a2,…,an where aiai means the trading price (buy or sell) of the Power Cube in the ii-th city. (1≤ai≤1091≤ai≤109)
It is guaranteed that the sum of all nn is no more than 5×1055×105.

Output

For each case, print one line with two integers —— the maximum profit and the minimum times of trading to get the maximum profit.

Sample Input

3
4
1 2 10 9
5
9 5 9 10 5
2
2 1
Sample Output

16 4
5 2
0 0

这个问题跟Codeforces 867E :Buy Low Sell High 问题(贪心、优先队列)
这个题差不多,可以先看下这篇文章,可以更好理解这个题

  • 思路:
    当我们到第i个城市时,可以假设前i - 1个物品我们全买了,将前i -1 个物品价值放入优先队列(从小到大,队首是最小值,如果值相同,就按照优先级大小),到第i个时,取队首元素,如果当前值 > 队首,那么我们就先卖出去,然后把当前的数加入两次队列,并赋予不同的优先级1、0
  • 1 优先级的意思是,若i - 1 > i > i + 1的值,那么我买入i -1卖出i再买入i再卖出i - 1跟我直接买i -1在i处卖出的价值是一样的,也相当于i是一个中间商,我们第1步算出的,只是一个暂时的有增益性的利润,如果遇到比i更大的第i + 1,我们就可以进行“反悔”操作,从而获得更大利润,并且这可以当作一步
  • 0 优先级则代表我真正买入当前物品,如果要卖的话,就要增加两步,一步是卖出,一步是买入,而1优先级该点只是一个中转站
  • 为什么我们要设置优先级呢?

举个例子:
2 5 9 6
将2压入队列,由于5 > 2我们把2卖出 并将{5,1}, {5,0}压入队列,然后我们遇到9,把{5 ,1}出队列然后9 - 5,这样我们发现,这其实是模拟的9-2的过程,也就是说我们之前的那个5还可以继续找比他更大的数卖出,比如卖给6,这样就达到了最大利润的目的,同时也防止记录买卖次数的混乱,也就是说,我们1优先级的5并不是真的卖出,只是替换了其中2的位置,我们当作2来卖,但是之前的利润我们先加上去,等下一个比{5,1}大的数时,再在之前5 - 2的利润上加上差价,所以在计算步数的时候,如果我们进行利润计算的时候,如果优先级高,就说明这一步只是中转,这一步只是我们自己加的,其实是没有的,而买卖的次数我们在第一次没有计算中转的时候,就已经把次数计算一次了,所以这一次中转不计入买卖次数,而优先级为0的,就是说在当前卖的时候,我们是已经进行了真正的买的操作的,再加上卖的一次,所以买卖次数要加2

-关于为什么要有优先级高的先出队,这是是为了防止在卖真正的物品时被干扰,更重要的是要依靠贪心的思想,具体证明我也不懂极其玄学,这里引用一下别的文章的说法

要想收入最高一定是在高价卖,低价买,如果我们在遇见一个高价就卖了,但是后面可能会有更高的价格,所以每当遇到一个高价,我就直接卖,等后面遇到更高的价格在更新。这样的贪心还是第一次遇见。要想收入最高一定是在高价卖,低价买,如果我们在遇见一个高价就卖了,但是后面可能会有更高的价格,所以每当遇到一个高价,我就直接卖,等后面遇到更高的价格在更新。

这篇文章我自己写起来有点晕,确实不知道怎么进行表述,凑和着看吧(捂脸)

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>

using namespace std;

typedef long long ll;

const int INF = 1e9 + 7;

struct sell
{
	int val, pri;
	//当前城市物品价值和对应的优先级
	bool operator < (const sell &a) const
	{
		if(val == a.val )	return pri < a.pri;
		return val > a.val;
		//如果当前物品价值相等(同一个物品进队两次,那么就让优先级高的先出)
	}
};

int main()
{
	std::ios::sync_with_stdio(false);
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		priority_queue <sell> q;
		ll ans = 0 , cnt = 0;
		int x;
		for(int i = 0; i < n; i++){
			cin>>x;
			if(!q.empty() && q.top().val < x){
				sell temp = q.top();
				ans += x - temp.val;
				//如果卖出的是之前买入的,那么就要有买入和卖出两步操作
				if(temp.pri == 0){
					cnt += 2;
				}
				q.pop();
				q.push({x, 0});
				q.push({x ,1});
			}
			else{
				q.push({x , 0});
			}
		}
		cout<<ans<<" "<<cnt<<endl;		
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值