联赛模拟测试12 B. trade

题目描述


分析

\(n^2\)\(dp\) 应该比较好想
\(f[i][j]\) 为当前在第 \(i\) 天剩余的货物数量为 \(j\) 时的最大收益
那么它可以由 \(f[i-1][j]\),\(f[i-1][j+1]\)\(f[i-1][j-1]\) 转移过来
用滚动数组能压掉一维
正解类似于可撤销贪心
我们开一个小根堆存放物品
每次取出堆中最小的物品和当前物品比较大小
如果比当前物品大,直接把当前物品扔进堆里
否则我们买入堆顶的物品,在当前卖出,累加贡献,弹出堆顶
并在堆里加入两个当前物品
第一个物品的含义是可以进行反悔操作
第二个物品的含义是反悔操作之后当前物品可以当作一个物品被重新买入

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e5+5;
int a[maxn],n;
std::priority_queue<int,std::vector<int>,std::greater<int> > q;
int main(){
	n=read();
	for(rg int i=1;i<=n;i++){
		a[i]=read();
	}
	long long ans=0;
	for(rg int i=1;i<=n;i++){
		if(q.empty() || a[i]<=q.top()){
			q.push(a[i]);
		} else {
			ans+=a[i]-q.top();
			q.push(a[i]);
			q.push(a[i]);
			q.pop();
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-10-12 08:40  liuchanglc  阅读(82)  评论(1编辑  收藏  举报