1. 程式人生 > >HDU 6438 Buy And Resell 思維,貪心

HDU 6438 Buy And Resell 思維,貪心

題意:n件物品,第i天,要麼花a[i]元買入物品i,或者以a[i]元賣出揹包中的物品.
n<=1e5,1<=a[i]<=1e9.問最大獲利,以及在最大獲利下的最少交易次數.

思維:不在第i天考慮是否買入,在第i天時看做獲得[1..i-1]物品的買入權利.
priority_queue維護當前能買的物品,set維護已經賣出去的物品.
現在在第i天只考慮是否能賣出a[i]來獲利.
若mn<a[i] 則買入mn 賣出a[i].此時賣出a[i]可能不是最優決定,但是可以依據後面的物品做撤銷操作.

如果某個mn過去已經被賣出過,顯然可以撤銷一次操作.(a,mn),(mn,b)-> (a,b).在把mn插入佇列即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll T,n,a[N];
priority_queue<ll> q;
multiset<ll> s;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++)	cin>>a[i];
		ll res=0,cnt=0;
		s.clear();
		while(!q.empty())	q.pop();
		for(int i=1;i<=n;i++){
			if(!q.empty()&&-q.top()<a[i]){
				int val=-q.top();
				res+=a[i]-val;
				cnt++;
				s.insert(a[i]);
				if(s.find(val)!=s.end())//x was selled before,now is buy. So it can be buy.  
				{
					s.erase(s.find(val));
					q.push(-val);
					cnt--;
				}
				q.pop();
			} 
			q.push(-a[i]);
		} 
		cout<<res<<' '<<cnt*2<<'\n';
			 
	}
	return 0;
}