2018牛客暑假多校二 D(贪心)

题目描述:

    你要按照顺序以此经过n个商店,每到达一个商店你可以购买一件物品,也可以出售你手中的商品。 同一时刻你手上最多拿一件商品。在第i个商店购买和出售的代价都是a[i]。 

    问你经过完n个商店后的最大收益。 同时,在最大化收益的前提下,求最小的交易次数。

题目分析:

    不难发现,要想使得利益最大,我们肯定是要在一个单调区域中的最小值中购入,再从该单调区域的最大值时转出。倘若发现了这个事实,则我们就可以将题目转化为一个判断两个单调区间的拐点为极大值还是极小值。(具体判断方法就是将某个点与之前一个和后一个点比较)

    倘若我们发现此时位于极小值,则我们需要更新价格最小cur。而当我们发现此时位置处于极大值,则更新最大利益sum=当前价格-最小价格,并将最小价格赋为-1代表没有最便宜的物品。

    而当我们取到最后一个点时,我们需要特判一下,如果当前是极大值点亦或者 当前不是极大值点,但拿了一个物品,则进行更新。

    值得留意的是,如果遇到连续相同的价格的时候(如数列[1,2,2,3,4]中的[2,2]),因为此时这些连续的价格对结果没有影响(甚至会阻碍我们的判断)因此我们考虑将这些连续相同的点去重。

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
typedef long long ll;
ll a[maxn];
ll tmp[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&tmp[i]);
        }
        int cnt=0;
        for(int i=1;i<=n;i++){//去重
            if(i==1){
                 a[++cnt]=tmp[i];
                 continue;
            }
            if(tmp[i]!=tmp[i-1]){
                a[++cnt]=tmp[i];
            }
        }
        ll cur=-1;
        ll sum=0,num=0;
        for(int i=1;i<=cnt;i++){
            if(i==1){
                if(a[i]<a[i+1]) cur=a[i];
                continue;
            }
            if(i==n){
                if(a[i]>a[i-1]) sum+=a[i]-cur,num+=2;
                else if(cur>=0) sum+=a[i]-cur,num+=2;
                continue;
            }
            if(a[i]>a[i-1]&&a[i]>a[i+1]){//当前处于极大值
                sum+=a[i]-cur,num+=2;
                cur=-1;
            }
            else if(a[i]<a[i-1]&&a[i]<a[i+1]){//当前处于极小值
                cur=a[i];
            }
        }
        cout<<sum<<" "<<num<<endl;
    }
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007265.html