ICPC 2023 Nanjing R L 题 Elevator

Problem Discription\] \\color{blue}{\\texttt{\[Problem Discription\]}} \[Problem Discription

来源:洛谷。侵权则删。

Analysis\] \\color{blue}{\\texttt{\[Analysis\]}} \[Analysis

贪心。优先运送楼层高的货物,在能装下的情况下尽量多装。

因为运送货物的代价仅和最高楼层的货物有关,假设一次运送货物时的最高楼层为 h h h,那么无论你剩下的货物楼层高还是低,代价都是 h h h 是固定的。

既然这样,我们应该优先把尽量高的货物都运送上去,剩下来的都是高度低的货物,后面的代价会减小。

排序后,从楼层高的货物开始装填,能装下就装下。注意处理特殊情况:即电梯剩余空间只有 1 1 1,但贪心需要装大小为 2 2 2 的货物时是装不下的。但是既然电梯空间还有剩余,就不应该浪费,应该找到下一个大小为 1 1 1 的货物。

指针来回的挪动可能会导致 T,因此按 w = 1 , 2 w=1,2 w=1,2 把货物分成两批,分别用一个指针来维护。这样可以保证时间复杂度为 O ( n ) O(n) O(n)。

总时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn),主要瓶颈在于排序。

但是,并没有做完!

这道题对代码能力的要求还是很高的。代码中有非常多容易出错的地方!相信这个贪心还是很多选手都能想到的,但是能不能写出来也是一个重要的问题。

具体的细节看代码中的注释。

Code \color{blue}{\text{Code}} Code

cpp 复制代码
const int N=1e5+100;

struct Marchandise{
	int amount,high;
	
	Marchandise(int a=0,int h=0){
		amount=a;high=h;
	}
	
	bool operator < (const Marchandise &c) const{
		return high>c.high;
	}
}a[N],b[N];//w=1,2 的分别存 

int n,r1,r2;
ll lim,ans;

int OZDY(){
	n=read();lim=read();
	ans=r1=r2=0;
	for(int i=1;i<=n;i++){
		int c=read(),w=read(),f=read();
		
		if (w==1) a[++r1]=(Marchandise){c,f};
		else b[++r2]=(Marchandise){c,f};
	}
	
	sort(a+1,a+r1+1);
	sort(b+1,b+r2+1);
	a[r1+1]=(Marchandise){0,0};
	b[r2+1]=(Marchandise){0,0};//没有这两行应该也没问题
	
	int l1=1,l2=1;
	ll remain=lim;
	while (l1<=r1&&l2<=r2){
		if (b[l2].high>=a[l1].high&&remain!=1){//楼层高的优先
			int tmp=(int)min((ll)b[l2].amount,remain>>1);
			
			if (remain==lim) ans+=b[l2].high;
			remain-=(tmp<<1);
			b[l2].amount-=tmp;//到这一行,remain 和 amount 至少一个被清零。
			
			if (!b[l2].amount){
				l2++;
				if (remain==0) remain=lim;
				continue;//注意一定要 continue,不然可能就直接进入下一个 if,开始装填 l2+1 了,但 l2+1 不一定是下一个装填的货物(可能是 l1,但不可能是 l2+2)。
			}
			if (l2>r2) break;
			
			if (remain==0){
				ans+=1ll*b[l2].high*((b[l2].amount<<1)/lim);//注意括号
				
				b[l2].amount%=(lim>>1);
				
				if (!b[l2].amount){
					l2++;
					remain=lim;
				}
				else{
					ans+=b[l2].high;
					remain=lim-(b[l2].amount<<1);
					l2++;
				}
			}
		}
		else{
			if (remain==1){
				a[l1].amount--;
				remain=lim;//这句话别忘了
				if (!a[l1].amount) l1++;
				continue;
			}//电梯剩余空间为 1 特殊处理
			
			int tmp=(int)min((ll)a[l1].amount,remain);
			
			if (remain==lim) ans+=a[l1].high;
			
			remain-=tmp;
			a[l1].amount-=tmp;
			
			if (!a[l1].amount){
				l1++;
				if (remain==0) remain=lim;//都恰好拿完 
				continue;
			}
			if (l1>r1) break;
			
			if (remain==0){
				ans+=1ll*a[l1].high*(a[l1].amount/lim);
				
				a[l1].amount%=lim;
				
				if (!a[l1].amount){
					l1++;
					remain=lim;
				}
				else{
					ans+=a[l1].high;
					remain=lim-a[l1].amount;
					l1++;
				}
			}
		}
	} //每进入循环一次,要么 l1 加一要么 l2 加一,保证时间复杂度
	
	if (remain==0) remain=lim; //注意维护关键变量(其实出循环后 remain 应该不会为 0,但是维护一下以免出乱子,反正不费事)
	
	while (l2<=r2){
		if (remain==1) remain=lim;//只剩下 w=2 的货物了,剩余的 1 空间没用了
		
		int tmp=(int)min((ll)b[l2].amount,remain>>1);//下面的语句几乎就是复制过来的。
		
		if (remain==lim) ans+=b[l2].high;
		remain-=(tmp<<1);
		b[l2].amount-=tmp;
		
		if (!b[l2].amount) l2++;//这里不需要 continue 了,因为下一个装的一定是 l2+1
		if (l2>r2) break;
		
		if (remain==0){
			ans+=1ll*b[l2].high*((b[l2].amount<<1)/lim);
			
			b[l2].amount%=(lim>>1);
			
			if (!b[l2].amount){
				l2++;
				remain=lim;
			}
			else{
				ans+=b[l2].high;
				remain=lim-(b[l2].amount<<1);
				l2++;
			}
		}
	}
	
	while (l1<=r1){
		int tmp=(int)min((ll)a[l1].amount,remain);
		
		if (remain==lim) ans+=a[l1].high;
		
		remain-=tmp;
		a[l1].amount-=tmp;
		
		if (!a[l1].amount) l1++;
		if (l1>r1) break; 
		
		if (remain==0){
			ans+=1ll*a[l1].high*(a[l1].amount/lim);
			
			a[l1].amount%=lim;
			
			if (!a[l1].amount){
				l1++;
				remain=lim;
			}
			else{
				ans+=a[l1].high;
				remain=lim-a[l1].amount;
				l1++;
			}
		}
	}//虽然代码看着很长,但是最主要的四段几乎就是复制粘贴,修改一些小细节
	
	printf("%lld\n",ans);
	
	return n;
}

int main(){
	int T=read();
	while (T--) OZDY();
	
	return 0;
}
相关推荐
可编程芯片开发12 分钟前
基于MPPT最大功率跟踪的离网光伏发电系统Simulink建模与仿真
算法
AI科技星21 分钟前
线性算子不是空间映射函数,是全域双螺旋场之间拉伸、旋转、耦合、坍缩的跨空间标准化变换载体《全域数学vs传统数学:人类文明进阶200讲》第80讲
线性代数·算法·矩阵·数据挖掘·回归·乖乖数学·全域数学
米罗篮24 分钟前
矩阵快速幂 (Exponentiation By Squaring Applied To Matrices)
c++·线性代数·算法·矩阵
dream_home840729 分钟前
图像算法模型NPU适配与算法服务实战指南
人工智能·python·算法·npu 图像服务
大鱼>1 小时前
多宠物家庭智能管理平台:云端架构与多设备协同实战
python·算法·iot·宠物
To_OC2 小时前
LC 22 括号生成:刷完这道题,我终于搞懂回溯剪枝了
javascript·算法·leetcode
To_OC2 小时前
LC 39 组合总和:回溯入门必刷题,我踩过的两个坑都在这了
javascript·算法·leetcode
数字杂技师2 小时前
每条推荐都很准,为什么我还是越刷越无聊?
算法
兰令水2 小时前
hot100【acm版】【2026.7.14打卡-java版本】
java·数据结构·算法·leetcode·面试
cpp_25013 小时前
P10098 [ROIR 2023] 地铁建设 (Day 2)
数据结构·c++·算法·贪心·二分答案·洛谷题解