Buy and Resell(贪心)

Buy and Resell

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


 

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个数里找出尽可能多的递增的非逆序对如(1,3),(1,2)。

一开始考虑这个题的时候也是先考虑了贪心,例如  1  2  10  9 本想从第一个数开始用这个数和前面的未匹配的最小的数匹配

因为如果中间间隔中间值是没有意义的   1 - 10   和  1 - 5  - 10 价值相同,徒增交易次数。所以考虑直接找最小的。

可是 1 2 10 9 这个样例,当走到2的时候,发现2要和1配对,那么问题就来了,2本不应该和1配对,但是现在强行配对了,该怎么办?如果想继续贪心下去就要解决这个问题。那么就可以考虑抢占的方式,就是说现在有  1 - 2  假如下次出现了5  那么如果现在2 -  5 要配对,我们发现2配过对,我们就直接让  1  - 5 配对释放 2。如果前面有两个2 , 都是最小值,其中一个2是配对的另个没有配对的话,肯定选择配对的先出来。因为获利都一样,这样使得交易次数少。至于抢占的实现,可以通过值来标记,也可以通过下标标记。

 

值标记:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int a[maxn],mk[maxn],n;
int X[maxn],cnt;
int main()
{
    int t; scanf("%d", &t);
    while(t--)
    {
        scanf("%d",&n);
        cnt = 1;
        memset(mk,0,sizeof(mk));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            X[cnt++] = a[i];
        }
        sort(X+1,X+cnt);
        cnt = unique(X+1,X+cnt)-X;
        for(int i = 1; i <= n; i++)
        {
            a[i] = lower_bound(X+1,X+cnt,a[i])-X;
        } 
        priority_queue <int,vector<int>,greater<int> > pq;
        ll ans = 0,tim = 0;
        for(int i = 1; i <= n; i++)
        {
            if(pq.empty()) 
            {
                pq.push(a[i]);
                continue;
            }
            if(pq.top() < a[i])
            {
                int x = pq.top();
                pq.pop();
                if(mk[x])  
                {
                    mk[x]--;    // 我们只关心个数,并不在意具体的位置。
                    ans += ll(X[a[i]]-X[x]);
                    mk[a[i]] ++;
                    pq.push(x);
                }
                else
                {
                    ans += ll(X[a[i]]-X[x]);
                    mk[a[i]]++;
                    tim++;
                }
                pq.push(a[i]);
            }
            else
            {
                pq.push(a[i]);
            } 
        }
        
        printf("%lld %lld\n",ans,2LL*tim);
    }
    return 0;
}

  

 下标标记:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int a[maxn],mk[maxn],n;
struct node{
    int x,id,s;
    node (){}
    node (int x, int id, int s):x(x),id(id),s(s){}
    bool operator < (const node nd) const 
    {
        if(x!=nd.x) return x > nd.x;
        return s < nd.s;
    }
};
int main()
{
    int t; scanf("%d", &t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
        }
        priority_queue <node> pq;
        ll ans = 0,tim = 0;
        for(int i = 1; i <= n; i++)
        {
            if(pq.empty()) 
            {
                pq.push(node(a[i],i,0));
                continue;
            }
            if(pq.top().x < a[i])
            {
                node tmp = pq.top();
                pq.pop();
                if(tmp.s)
                {
                    tmp.s = 0;
                    ans += ll(a[i]- tmp.x);
                    pq.push(tmp);
                }
                else
                {
                    ans += ll(a[i]- tmp.x);
                    tim++;
                }
                pq.push(node(a[i],i,1));
            }
            else
            {
                pq.push(node(a[i],i,0));
            } 
        }
        
        printf("%lld %lld\n",ans,2LL*tim);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值