首页 > 其他分享 >CF436E Cardboard Box 题解

CF436E Cardboard Box 题解

时间:2023-02-24 13:56:45浏览次数:40  
标签:Box int 题解 long 一关 10000000000ll push CF436E include

一道经典的反悔贪心题。

考虑每次选择使总星数加一,那么总共有四种情况。

一、对于一关没有星,选一颗星,代价为 \(a_i\)。

二、对于一关有一颗星,再选一颗星,代价为 \(b_i-a_i\)。

三、对于一关有一颗星,选择退回这颗星,并再另一个没星的关卡选两颗星,代价为 \(-a_i+b_j\)。

四、对于一关有两颗星,退回一颗星,并再另一个没星的关卡选两颗星,代价为 \(-b_i+a_i+b_j\)

那么维护五个优先队列,分别为 \(a_i,b_i-a_i,-a_i,b_j,-b_i+a_i\),每次取四种情况的最小值来选即可。

#include<iostream>
#include<cstdio>
#include<queue>
#define int long long
using namespace std;
const int N=3e5+5;
int n,w,a[N],b[N],vis[N];
long long ans=0;
struct node
{
	int name;
	int data;
};
bool operator <(node fi,node se)
{
	return fi.data>se.data;
}
priority_queue<node>q1,q2,q3,q4,q5;
signed main()
{
	scanf("%lld%lld",&n,&w);
	q1.push({0,10000000000ll});
	q2.push({0,10000000000ll});
	q3.push({0,10000000000ll});
	q4.push({0,10000000000ll});
	q5.push({0,10000000000ll});
	for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]),q1.push({i,a[i]}),q5.push({i,b[i]});
	for(int i=1;i<=w;i++)
	{
		int num1=q1.top().data,num2=q2.top().data,num3=q5.top().data+q3.top().data,num4=q5.top().data+q4.top().data;
		if(num1<=num2&&num1<=num3&&num1<=num4)
		{
			ans+=num1;
			int id=q1.top().name;
			vis[id]=1;
			q3.push({id,-a[id]});
			q2.push({id,b[id]-a[id]});
		}
		else if(num2<=num1&&num2<=num3&&num2<=num4)
		{
			ans+=num2;
			int id=q2.top().name;
			vis[id]=2;
			q4.push({id,a[id]-b[id]});
		}
		else if(num3<=num2&&num3<=num1&&num3<=num4)
		{
			ans+=num3;
			int id=q5.top().name,id2=q3.top().name;
			q4.push({id,a[id]-b[id]});
			q1.push({id2,a[id2]});
			q5.push({id2,b[id2]});
			vis[id]=2;
			vis[id2]=0;
		}
		else
		{
			ans+=num4;
			int id=q5.top().name,id2=q4.top().name;
			q4.push({id,a[id]-b[id]});
			q3.push({id2,-a[id2]});
			q2.push({id2,b[id2]-a[id2]});
			vis[id]=2;
			vis[id2]=1;
		}
		while(q1.top().name!=0&&vis[q1.top().name]!=0)q1.pop();
		while(q2.top().name!=0&&vis[q2.top().name]!=1)q2.pop();
		while(q3.top().name!=0&&vis[q3.top().name]!=1)q3.pop();
		while(q4.top().name!=0&&vis[q4.top().name]!=2)q4.pop();
		while(q5.top().name!=0&&vis[q5.top().name]!=0)q5.pop();
	}
	printf("%lld\n",ans);
	for(int i=1;i<=n;i++)printf("%lld",vis[i]);
	return 0;
}

标签:Box,int,题解,long,一关,10000000000ll,push,CF436E,include
From: https://www.cnblogs.com/gmtfff/p/cf436e.html

相关文章

  • CF204E Little Elephant and Strings 题解
    由于是多个串,还与每个子串的信息有关,很容易想到用SA或广义SAM。这里选择用SA。首先先把字符串转化为数组,连接起来,中间用一些不会出现的数。处理出后缀数组与\(height......
  • P5842 [SCOI2012]Blinker 的仰慕者 题解
    题意简述:求\([l,r]\)内各个数位积为\(k\)的数的和。解:在看题解前,请先确认自己是否精通了数位dp模板题,否则会很难理解。对于朴素的数位dp,我们可以记录\(f_{i,j......
  • P5416 [CTSC2016]时空旅行 题解
    首先题中的\(y,z\)好像没啥用……首先对于每一次询问,要求\(\min((x_0-x_i)^2+c_i)\)设\((x_0-x_i)^2+c_i=ans\)。那么\(x_0^2+x_i^2-2x_0x_i+c_i=ans\)所以\(x_0......
  • P7862 [COCI2015-2016#2] DRŽAVA 题解
    适当进行骗分是真的有用。\(40pts\):对于每两个点建立一条边,然后在贪心每次求最小边,在期间进行01背包即可,01背包用于处理模数。设\(dp_{i,j}\)代表以\(i\)为编号的一......
  • P1379 八数码难题 题解
    IDA*练习题由于题目问最小步数,很好想到可以用迭代式加深搜索,或是广搜,这里用的是深搜。枚举每次搜索的深度,也就是移动的步数,然后正常深搜,若达到目标解,返回\(\text{ture}......
  • P3213 [HNOI2011]勾股定理 题解
    据说是NP问题。很明显我们要先预处理出来勾股数对。但由于数过于大,所以常规的枚举是解决不了问题的。但也貌似没有什么很好的办法可以立马找到一个数的勾股数对。所以......
  • P3989 [SHOI2013]阶乘字符串 题解
    由于一些不可抗拒的原因,\(n\ge22\)无解。那么只用考虑\(n\le21\)的情况即可。由于\(n\)的范围缩小,导致状压又可以重新使用,所以考虑状压。设\(f_i\)为\(i\)中......
  • AT655 玉座の間 题解
    首先我们要学习一下费用流。费用流是什么呢,可以理解为边带权值的网络流。那么最小费用最大流,是指在满足最大流的情况下的最小费用。那么我们就要实现这个过程。首先对......
  • P3997 [SHOI2013]扇形面积并 题解
    理解题意后可以把题目看成一个覆盖线段的问题。对于点在\(-m\)上,看成在\(m\)上。对于\(l<r\),不用处理。对于\(l>r\),将问题看成\((l,m)\)和\((-m+1.r)\)两个区......
  • P5616 [MtOI2019]恶魔之树 题解
    期望就是来搞笑的。由于有最小公倍数,所以可以想到分解质因数,对于多个数求最小公倍数,取每个质因子的最大指数,最后相乘即可。既然都知道了这个,那么就想到先统计每个数的个......