HDU 6438 Buy And Resell 思維,貪心
阿新 • • 發佈:2018-11-02
題意: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; }