可撤销贪心

Posted uid001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可撤销贪心相关的知识,希望对你有一定的参考价值。

1. CF 867E Buy Low Sell High

大意: 第$i$天可以花$a_i$元买入或卖出一股或者什么也不干, 初始没钱, 求$n$天后最大收益.

 

用堆维护最小值, 假设当前考虑的值为$a_i$, 堆中最小值为$t$, 则卖出贡献$a_i-t$, 若贡献$>0$直接加上, 然后再填进去一个$a_i$, 之后若有更优值$x$, 总贡献会变为$x-a_i+a_i-t$, 也就相当于进行反悔操作.

#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;
typedef long long ll;

int main() {
	int n;
    scanf("%d", &n);
    priority_queue<int,vector<int>,greater<int> > q;
    ll ans = 0;
	while (n--) {
        int t;
        scanf("%d", &t);
        q.push(t);
        if (t>q.top()) {
            ans += t-q.top();
            q.pop();
            q.push(t);
        }
    }
    printf("%lld\n", ans);
}

 

2. luogu P1484 种树

cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#define REP(i,a,n) for(int i=a;i<=n;++i)

using namespace std;
typedef long long ll;
const int N = 500010;

bool vis[N];
struct node {
	int u, d;
	bool operator < (const node& rhs) const {
		return d<rhs.d;
	}
}a[N];

int l[N], r[N];
ll w[N];
priority_queue<node> q;

int main() {
	int n, k;
	scanf("%d%d", &n, &k);
	REP(i,1,n) {
		node x{i};
		scanf("%d", &x.d);
		q.push(x);
		l[i] = i-1, r[i] = i+1, w[i]=x.d;
	}
	ll ans = 0;
	REP(i,1,k) {
		while (vis[q.top().u]) q.pop();
		node t = q.top(); q.pop();
		if (t.d<0) break;
		ans += t.d;
		w[t.u] = t.d = w[l[t.u]]+w[r[t.u]]-w[t.u];
		vis[l[t.u]] = vis[r[t.u]] = 1;
		l[t.u] = l[l[t.u]];
		r[l[t.u]] = t.u;
		r[t.u] = r[r[t.u]];
		l[r[t.u]] = t.u;
		q.push(t);
	}
	printf("%lld\n", ans);
}

 

3. ZOJ 4043

第一行给n个数,第二行给m个数,m<=n,从n个数中取m个数和第二行的m个数匹配,匹配花费abs(ai-bj),求最小匹配花费

#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int Case,n,m,i,ce,x;ll ans;
struct E{int x,y;E(){}E(int _x,int _y){x=_x,y=_y;}}e[200010];
inline bool cmp(const E&a,const E&b){return a.x<b.x;}
int main(){
  scanf("%d",&Case);
  while(Case--){
    priority_queue<ll,vector<ll>,greater<ll> >A,B,C;
    scanf("%d%d",&n,&m);
    ce=0;
    while(n--){
      scanf("%d",&x);
      e[++ce]=E(x,0);
    }
    while(m--){
      scanf("%d",&x);
      e[++ce]=E(x,1);
    }
    sort(e+1,e+ce+1,cmp);
    ans=0;
    for(i=1;i<=ce;i++){
      ll x=e[i].x;
      if(e[i].y==0){
        if(!C.empty()){
          ll t=C.top();
          C.pop();
          ans+=x+t;
        }else if(!B.empty()){
          ll t=B.top();
          if(t+x<0){
            B.pop();
            ans+=x+t;
            A.push(-t-x-x);
          }else A.push(-x);
        }else A.push(-x);
      }else{
        if(!A.empty()){
          ll t=A.top();
          A.pop();
          ans+=x+t;
          B.push(-t-x-x);
        }else C.push(-x);
      }
    }
    printf("%lld\n",ans);
  }
}

 

以上是关于可撤销贪心的主要内容,如果未能解决你的问题,请参考以下文章

Contig|scaffold|N50|L50|NG50|贪心算法|de bruiji graph|

贪心算法:划分字母区间

763. 划分字母区间-贪心算法

Swift3.0学习实践-一个简单的画板(七色轨迹可撤销可清除带橡皮擦)

Swift3.0学习实践-一个简单的画板(七色轨迹可撤销可清除带橡皮擦)

Swift3.0学习实践-一个简单的画板(七色轨迹可撤销可清除带橡皮擦)