题意:

给出n天,每天可以买进或者卖出或者不买不卖,价格是这一天的权值,问最多利润是多少,如果利润相同的有多种,取操作数最小的那种。输出最多利润与操作数。

思路:

这道题队友似乎最后想出来了啊?可是来不及写了…

用小顶堆维护。

如果当前输入为x,当堆为空或者堆顶元素大于等于x时,把x放入堆中(因为如果利润相同要操作数最小,所以等于也要放入堆中,而不是买卖)。

否则删除堆顶元素,将x在堆中放两遍,

  • 抵消这一次的卖出,用后面更大的数来换掉它;
  • 把这一次当成买入。

如何统计操作数呢?

因为会出现抵消的情况,那么抵消这里应该不能算,所以开个vis数组标记一下。

又因为要使操作数最小,所以抵消的时候如果有相同数值,就随便抵消哪一个,而不是一定要上一个出现卖的那个地方。所以数组下标是权值。

手动模拟一下就会发现很有道理。

代码:

typedef long long ll;
map<ll,int>vis;
int main()
{
    int t,n;
    ll x;
    scanf("%d",&t);
    while(t--)
    {
        priority_queue<ll,vector<ll>,greater<ll> >q;
        vis.clear();
        scanf("%d",&n);
        ll ans=0;
        int num=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&x);
            if(q.empty()||q.top()>=x)
                q.push(x);
            else
            {
                ans+=x-q.top();
                if(vis[q.top()])
                    vis[q.top()]--;
                else num+=2;
                q.pop();
                vis[x]++;
                q.push(x);
                q.push(x);
            }
        }
        printf("%lld %d\n",ans,num);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

CodeForces1011E 裴蜀定理 Previous
树上启发式合并 Dsu on tree Next