P7371 [COCI 2018/2019 #4] Kisik 题解

题目链接

我的博客

思路

首先需要明确的是这道题要求什么。

因此充气的范围也是一个矩形区域。

所以这道题要求的是 \(W \times H\) 的最小值。那么考虑贪心。

由题可得,\(W\) 是所有宽度的总和,\(H\) 是所有高度的最大值。所以我们的贪心思路是:在最大的楼房高度尽可能小的情况下,让每个楼房的宽度尽可能小。

于是我们想到了按照楼房高度排序,从小到大选择,这样可以保证最大高度最小。在此基础上,对于高度更高的楼房,我们每次取出最宽的一个楼房,换进去一个高度更大、但是宽度更小的楼房,更新答案,此过程可以用优先队列来维护。最终答案即为最小值。

时间的瓶颈在于优先队列的排序,因此时间复杂度 \(O(n \log n)\)

总结

  1. 按照高度从小到大排序。
  2. 遍历更高的楼房。每次取出之前最宽的一个楼房,换进去一个高度更大、但是宽度更小的楼房,更新答案。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define int long long 
#define ___ __int128
#define INF 0x3f3f3f3f3f3f3f3f 
inline int Read(){
    int x=0,f=1;
    char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-48;c=getchar();}
    return x*f;
}
inline void Write(int x){
	if(x<0) {putchar('-');x=-x;}
	if(x>9) Write(x/10);
	putchar(x%10+'0');
}
const int N=1e6+10;
int n,k,ans;
int w,h;
struct node{
	int w,h;//记录宽度、高度
}a[N];
bool cmp(node A,node B){return A.h<B.h;}//按照高度排序
priority_queue<int> q;//优先队列,默认大根堆
signed main(){
	n=Read();k=Read();
	for(int i=1;i<=n;i++){
		a[i].w=Read();
		a[i].h=Read();
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=k;i++){//先把高度最小的 K 个选上
		w+=a[i].w;
		h=max(h,a[i].h); 
		q.push(a[i].w); 
	}
	ans=w*h;
	for(int i=k+1;i<=n;i++){
		w-=q.top();q.pop();//取出宽度最大的
		w+=a[i].w;q.push(a[i].w); //把当前宽度放进去
		h=max(h,a[i].h);//h=a[i].h
		ans=min(ans,w*h);
	}
	printf("%lld\n",ans);
	return 0;
}
posted on 2025-11-05 07:49  _Liuliuliuliuliu  阅读(6)  评论(0)    收藏  举报