1. 程式人生 > >優先佇列+貪心

優先佇列+貪心

Buy and Resell

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


 

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

Source

 題意:有n天,每天都有一個股票價格ai,你每天可以花ai買下當天的股票,也可以以ai價格賣掉你手中的股票(但是最多隻能賣一張或者買一張,且不能又買又賣,可以不買不賣) 求最大收益,且在最大收益情況下最小操作次數

分析:

這道題就是求一個收益最高且最短的合法括號序列,左括號表示當天買入,右括號表示當天賣出

開兩個優先佇列,其中一個存每一對括號,按照右括號的值排序,頂端最小,另一個優先佇列存單獨的左括號,仍然按照值排序,頂端最小

這樣對於當前第i天的股票ai,有三種方案:

①作為單一的左括號

②最頂端的一對括號中,將右括號替換成當前這個括號,並將原來的右括號單獨拉出來作為一個單一的左括號;

③和頂端的單一左括號匹配成為一對括號;

AC code:

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include<queue>
using namespace std;
typedef long long ll;
struct Node{
int x,y;
bool operator<(const Node&a)const
{
    return y>a.y;
}
};
priority_queue<Node>q1,q2;
Node now,temp;
int main()
{
    int t,n;
    int s1,s2;
    ll val;
    scanf("%d",&t);
    while(t--){
        while(!q1.empty()) q1.pop();
        while(!q2.empty()) q2.pop();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            s1=s2=0;
            scanf("%lld",&val);
            if(!q1.empty())
              s1=val-q1.top().y;///s1為和左括號匹配後增加的利益
            if(!q2.empty())
              s2=val-q2.top().y;///s2為替換右括號後增加的利益
            if(s1<=0&&s2<=0)
            {
                now.y=val;
                q1.push(now);///當兩種方案都不能產生利益時,說明val很小,於是把它作為左括號
            }
            else if(s2>=s1)///顯然s2>s1時應替換右括號,但原本的右括號不能捨棄,它可能成為下一個左括號
            {           ///當s2==s1時兩種方案產生利益相同,但替換右括號可以產生新的左括號,因此方案二好一些
                now=q2.top();
                q2.pop();    
                temp=now;    
                now.y=val;   
                q2.push(now);
                q1.push(temp);
            }
            else           ///否則直接和左括號匹配
            {
                now=q1.top();
                q1.pop();
                now.x=now.y;
                now.y=val;
                q2.push(now);
            }
        }
        ll ans=0,cnt=0;
        while(!q2.empty())
        {
            ans+=q2.top().y-q2.top().x;
            cnt++;
            q2.pop();
        }
        printf("%lld %lld\n",ans,2*cnt);
    }
    return 0;
}

最後還貼出一個和它比較像的題:

White Cloud has built n stores numbered from 1 to n.
White Rabbit wants to visit these stores in the order from 1 to n.
The store numbered i has a price a[i] representing that White Rabbit can spend a[i] dollars to buy a product or sell a product to get a[i] dollars when it is in the i-th store.
The product is too heavy so that White Rabbit can only take one product at the same time.
White Rabbit wants to know the maximum profit after visiting all stores.
Also, White Rabbit wants to know the minimum number of transactions while geting the maximum profit.
Notice that White Rabbit has infinite money initially.

輸入描述:

The first line contains an integer T(0<T<=5), denoting the number of test cases.
In each test case, there is one integer n(0<n<=100000) in the first line,denoting the number of stores.
For the next line, There are n integers in range [0,2147483648), denoting a[1..n].

輸出描述:

For each test case, print a single line containing 2 integers, denoting the maximum profit and the minimum number of transactions.

示例1

輸入

1
5
9 10 7 6 8

輸出

3 4

本題與上面的題目不同在於上面的題拿在手上的可以是多個物品,而這題拿在手上的至多一個物品,所以這題就是一個簡單的貪心,

Ac code:

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100001;
typedef long long ll;
int main()
{
    ll dp[maxn];
    int t;
    int n;
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>t;
    while(t--)
    {
    memset(dp,0,sizeof dp);
    cin>>n;
    for(ll i=1;i<=n;i++)
        cin>>dp[i];
    ll cnt=0,cas=0;
    int state=0;
    for(ll i=1;i<=n;i++)
    {
        if(dp[i]<dp[i+1]&&!state)///買,並且手中沒有物品
        {
            cnt-=dp[i];
            cas++;
            state=1;
        }
        else if(dp[i]>dp[i+1]&&state)///賣,並且手中有一個物品
        {
            cnt+=dp[i];
            state=0;
        }
        else continue;
    }
    cout<<cnt<<' '<<2*cas<<endl;
    }
    return 0;
}