1. 程式人生 > >2018中國大學生程序設計競賽 - 網絡選拔賽 1001 - Buy and Resell 【優先隊列維護最小堆+貪心】

2018中國大學生程序設計競賽 - 網絡選拔賽 1001 - Buy and Resell 【優先隊列維護最小堆+貪心】

input 不出 def pop earch 無限 math 上交 要去

題目傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=6438

Buy and Resell

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

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 (T250), indicating the number of test cases. For each test case:
The first line has an integer n. (1n105)
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. (1ai109)
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 Source 2018中國大學生程序設計競賽 - 網絡選拔賽

題意概括:

有 N 個商店,小商按順序走過每個商店(不能回頭),在每個商店它可以選擇在那個商店以那個商店的價格買入或者賣出一件物品,當然他也可以選擇不買不賣。小商的背包容量無限大。我需要做的是使得小商走過所有商店之後獲得最大的利潤以及他所花費的交易次數。

解題思路:

之前牛客暑假多校的一個變形,不只是能拿一個了,可以拿很多個。這道題的解法也是貪心,但是與之前那道很不一樣。

首先他可以買多個商品,也就是說,他可能有反悔的機會,也就是說雖然他前面已經把那件商品賣掉了,但如果後面有比前面更優的選擇,他其實可以反悔,之前不賣不出去而是等到更優的時候再賣。

而我們要做的就是為他提供一個可以反悔的機會。

這時候就需要用 STL 裏的優先隊列來維護一個最小堆了,而最小堆裏面的是買入的商品(這裏指的買入的商品其實更確切的說是加上交換得來的商品,但交換而來的商品要區別於直接花錢買的商品,所以要打上標記),堆頂的值是這些商品中價格最小的。

有了這個反悔神器,小商每到一家商店就可以把商店的交易價和堆頂的值做比較,如果比堆頂的值大的則買入(拿便宜的換貴的嘛),盈利值就是貴的和便宜的價錢之差,並把當前這家商店的商品丟進堆裏,那麽原本堆頂用於交換的那件呢怎麽辦呢?這就要看它是當時花錢買來的還是換來的了,如果是花錢買來的就直接不要啦並且操作數+1;如果是交換而來的,那麽就去掉標記重新入堆(這種情況下我們發現其實它相當於一個中轉物品了,這件貴的物品其實是跟交換它的那件物品進行交換了,而不是跟它,所以操作數不變並且要去掉標記)。如果當前商店的交易價比堆頂的要小呢,當然丟進堆裏啦(反正現在丟進堆裏又不用錢),如果後面有機會用高價換掉它的話又賺一波。所以有了這個時光機,商人可是穩賺不賠的啊。

AC code:

技術分享圖片
 1 #include <bits/stdc++.h>
 2 #define INF 0x3f3f3f3f
 3 #define ll long long int
 4 using namespace std;
 5 const int MAXN = 1e5+10;
 6 int N;
 7 struct tp{
 8     int x, v;
 9     bool sell;
10     bool friend operator<(tp a, tp b)
11     {
12         if(a.v == b.v) return !a.sell;
13         return a.v > b.v;
14     }
15 };
16 int main()
17 {
18     int T_case, a;
19     scanf("%d", &T_case);
20     while(T_case--)
21     {
22         priority_queue<tp> Q;
23         scanf("%d", &N);
24         scanf("%d", &a);
25         tp temp;
26         temp.x = 1;
27         temp.v = a;
28         temp.sell = false;
29         Q.push(temp);
30         ll ans = 0, time = 0;
31         for(int i = 2; i <= N; i++)
32         {
33             scanf("%d", &a);
34             temp.sell = false;
35             if(a > Q.top().v)
36             {
37                 tp top = Q.top();
38                 Q.pop();
39                 ans+=a-top.v;
40                 if(top.sell)
41                 {
42                     top.sell = false;
43                     Q.push(top);
44                 }
45                 else time++;
46                 temp.sell = true;
47             }
48             temp.x = i;
49             temp.v = a;
50             Q.push(temp);
51         }
52         printf("%lld %lld\n", ans, time*2);
53     }
54     return 0;
55 }
View Code

2018中國大學生程序設計競賽 - 網絡選拔賽 1001 - Buy and Resell 【優先隊列維護最小堆+貪心】