HDU 6438 Buy and Resell(优先队列+思维)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37025443/article/details/82467723

Buy and Resell

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2221    Accepted Submission(s): 829

题目链接
 

Problem Description

The Power Cube is used as a stash of Exotic Power. There are n cities numbered 1,2,…,n where allowed to trade it. The trading price of the Power Cube in the i-th city is ai 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 i-th city and choose exactly one of the following three options on the i-th day:

1. spend ai dollars to buy a Power Cube
2. resell a Power Cube and get ai 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 n 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 T (T≤250), indicating the number of test cases. For each test case:
The first line has an integer n. (1≤n≤105)
The second line has n integers a1,a2,…,an where ai means the trading price (buy or sell) of the Power Cube in the i-th city. (1≤ai≤109)
It is guaranteed that the sum of all n is no more than 5×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

Hint

In the first case, he will buy in 1, 2 and resell in 3, 4. profit = - 1 - 2 + 10 + 9 = 16 In the second case, he will buy in 2 and resell in 4. profit = - 5 + 10 = 5 In the third case, he will do nothing and earn nothing. profit = 0

 题意:

有n个地方,给你一节商品在这n个地方的价格

你按顺序从1走到n,在一个地方,你可以选择

1.买入有且仅有一个商品

2.卖出有且仅有一个商品

3.不进行交易

问你你最后获得的最大的收益,以及在收益最大的前提下最小的交易次数

解析:

一开始我一直执着于每一个数的加减号,后来看了题解.....

题解维护的是一个小顶堆,代表[1,i-1]内价格最低的地方

然后对于a[i],如果a[i]<=top().price,表示a[i]找不到价格比它小的地方,直接将a[i],push进去

否则,就要看top()这个地方有没有已经被交易过

如果top()未发生交易,那么我们就直接计算答案,然后将a[i],push进去。

注意!!这里是push两次,第一次push进去的点是用来反悔用的。因为可能后面还有更优的解!!

譬如1,2,3,,2遍历完后,对于3,我们发现虽然1与2进行交易,但是显然1与3才是最优解,

那么我们就需要有一个点是用来回溯的,也就是说,

你一旦选择了这个点,那么你是用a[i]替换top()表示的点来去跟top()之前交易的点交易

因为刚好查分满足-1+2-2+3=-1+3,所以直接ans+=a[i]-top().val,效果是一样的,就是把2这个点给抵消

第二次push的点才是真正将top()表示的点给卖出去

譬如1 2 3 5

2结束后,堆里面2(1),2

对于3遍历完后,1与3交易,堆里面变成2,3(1),3

然后5再与2交易,那么这样2就被真正交易了

最后再把交易次数time+=2

然后再是如果top(),出来的点是已经被交易的点,那么我们直接把它替换掉就可以了,即接受它的反悔,

之后同样计算ans,push两次

注意这里因为同时需要计算最小的交换次数,这里就不需要将time+=2,因为这里没有发生新的交易,只是替换了交易

哎...这种思维题想了一天想不出来.....脑子还是太笨了.....继续努力了..

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5+10;

typedef struct node
{
	int x;
	int pre;
	friend bool operator <(node a,node b)  //优先队列是相反的
	{
		if(a.x==b.x) return a.pre>b.pre;
		return a.x>b.x;
	}
}node;

priority_queue<node> mq;
int a[MAXN];

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
	    while(!mq.empty()) mq.pop();
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		ll ans=0;
		int time=0;
		mq.push(node{a[1],INF});
		for(int i=2;i<=n;i++)
        {
            node u=mq.top();
            if(a[i]<=u.x) mq.push(node{a[i],INF});
            else
            {
                mq.pop();
                ans+=1ll*(a[i]-u.x);
                mq.push(node{a[i],INF});
                if(u.pre!=INF)
                {
                    mq.push(node{a[i],u.pre});
                }
                else
                {
                    mq.push(node{a[i],u.x});
                    time+=2;
                }
            }
        }
        printf("%lld %d\n",ans,time);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/82467723