反悔贪心


就是说反悔贪心有两种,一种反悔堆是需要你手动去把之前的劣解换出来,一种反悔自动机是通过类似网络流反向边一样的办法让你的贪心自动实现反悔。


P2949

贪心的选取大的,如果插不进去就把时间在它前面并且价值在它后面的换出来。为了手动换需要按时间顺序选,同时维护一个小根堆。

点击查看代码
#include
using namespace std;
#define cs const
#define in read()
inline int read(){
	int p=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-48;c=getchar();}
	return p*f;
}
cs int N=100005;
int n,siz;
struct node{
	int p,d;
	bool operator<(const node &b){
		return d,greater>q;
long long ans;
signed main(){
	n=in;
	for(int i=1;i<=n;i++)
		a[i].d=in,a[i].p=in;
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
		if(siz+1<=a[i].d)ans+=a[i].p,q.push(a[i].p),siz++;
		else if(q.top()

CF865D

贪心的让一个位置卖出时选择前面最小的买入,为了避免 1 2 100 的情况让这个位置卖出后在买入的堆里插入卖出位置的值,通过 \((a[k]-a[j])+(a[j]-a[i])=a[k]-a[i]\) 实现反悔。

点击查看代码
#include
using namespace std;
#define cs const
#define in read()
inline int read(){
	int p=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-48;c=getchar();}
	return p*f;
}
cs int N=300005;
int n,siz,a[N];
priority_queue,greater>q;
long long ans;
signed main(){
	n=in;
	for(int i=1;i<=n;i++)a[i]=in;
	for(int i=1;i<=n;i++){
		if(!q.empty()&&a[i]>q.top())
			ans+=a[i]-q.top(),q.pop(),q.push(a[i]);
		q.push(a[i]);
	}
	cout<

BZOJ2151

贪心的选取美观度最大的位置并把前驱后缀删除,同时把原位置换成 \(a[pre]+a[nxt]-a[i]\),再次选到这个位置 ans 加上这个权值就代表去掉这个位置换成两边的。

点击查看代码
#include
using namespace std;
#define cs const
#define in read()
inline int read(){
	int p=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-48;c=getchar();}
	return p*f;
}
cs int N=300005;
int n,m,a[N],pre[N],nxt[N];
struct node{
	int d,pos;
	friend bool operator<(const node &a,const node &b){
		return a.dq;
long long ans;
bool vis[N];
signed main(){
	n=in,m=in;
	for(int i=1;i<=n;i++)a[i]=in,pre[i]=i-1,nxt[i]=i+1,q.push({a[i],i});
	pre[1]=n,nxt[n]=1;
	if(n/2

发现这些题都用到了堆,原因大概是可以快速选出局部最优决策吧。

P2107