专栏文章

题解:P12015 [NOISG 2025 Finals] 怪物

P12015题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@mip9i3zw
此快照首次捕获于
2025/12/03 08:21
3 个月前
此快照最后确认于
2025/12/03 08:21
3 个月前
查看原文

思路

算法是二分贪心
先把怪物和地雷坐标排序
我们先分情况讨论如何打死怪物,由题意知可分为两种,即直接减生命值,用地雷炸死。
第一种,显然,如果怪物自身生命值小于或等于距离怪物最近的地雷的距离,就直接减去。
第二种,我们可以再分为两种情况,即距离左右两端地雷的距离不等或相等,前者可以看距离哪个短就走到哪个地雷再标记一下,而后者如果左边的地雷被标记了就优先到左边的,否则就到右边的并标记,这样可以利用之前被标记的地雷,减少花费。
其中的左右距离相等很难想到,要细心。
至于二分,我们可以使用 upper_bound 函数,它可以在已排序的范围内查找第一个大于给定值的元素,以便于我们找到怪兽左右边的地雷的坐标。
代码如下:
CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
ll n,k,x[N],l,r,lx,rx,ans,cnt,vis[N];
struct stu{
	ll a,h;//要注意a是坐标,h是生命值!!! 
}d[N];
bool cmp(stu a,stu b){
	return a.a<b.a;
}
int main(){
	cin>>n>>k;
	for(ll i=1;i<=n;i++){
		cin>>d[i].a>>d[i].h;
	}
	for(ll i=1;i<=k;i++){
		cin>>x[i];
	}
	sort(d+1,d+1+n,cmp);//排序 
	sort(x+1,x+1+k);
	for(ll i=1;i<=n;i++){
		r=upper_bound(x+1,x+1+k,d[i].a)-x;//在已排序的范围内查找第一个大于给定值的元素
		l=r-1;//左右地雷的坐标 
		lx=d[i].a-x[l];
		rx=x[r]-d[i].a;//距离左右地雷的距离
		if(x[l]<=0) lx=1e18;//防止越界 
		if(x[r]<=0) rx=1e18;
		if(min(rx,lx)>=d[i].h){//第一种情况 
			ans+=d[i].h;
		}else if(rx!=lx){//第二种情况 
			if(rx>=lx){
				ans+=lx;
				vis[l]=1;
			}else{
				ans+=rx;
				vis[r]=1;
			}
		}else{//左右相等 
			if(vis[l]==1){
				ans+=lx;
			}else{
				ans+=rx;
				vis[r]=1;
			}
		}
//		cout<<lx<<" "<<rx<<' '<<ans<<"\n";
	}
	for(ll i=1;i<=k;i++){
		ans+=vis[i];//引爆被标记的的地雷 
	}
	cout<<ans;
	return 0;
}
//1 2 3 4 5
//		*
//  2   5 4
完结撒花。

评论

3 条评论,欢迎与作者交流。

正在加载评论...