题解:P14205 [ROI 2016 Day1] 要塞防御

题目传送门

题意简述

共有 \(n\) 个防御墙,对于每个防御墙有 \(a_i\) 个敌人入侵。共有 \(s\) 名守卫,每一个人在 \(i\) 号墙能够抵御 \(k_i\) 名敌人。最小化无法抵御的敌人数量。

思路简析

敌人的数量为 \(\displaystyle \sum_{i=1}^{n} x_i\) 显然是一个定值。因此要最小化无法抵御的敌人数量,只需最大化能够抵御的敌人数量即可。

如何最大化敌人的数量?很容易贪心策略是使得每个守卫抵御的敌人数量尽可能多。从而想到将 \(k\) 从大到小枚举。但是对于每一个防御墙,最后一个守卫抵御的敌人数量是 \(a_i \bmod k_i\) 个。随即想到了可使用优先队列维护。

Code

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pll pair<ll,ll>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
int n;
ll s,a,k,t,ans;
priority_queue<pll>q;
int main()
{
	ios;cin>>n>>s;
	for(int i=1;i<=n;i++)
	{
		cin>>a>>k;
		q.push({k,a});//按 k 从大到小排序
		ans+=a;
	}
	while(!q.empty())
	{
		if(!s)break;
		k=q.top().fi;
		a=q.top().se;
		q.pop();
		if(a)
		{
			t=a/k;
			ans-=min(s,t)*k;
			a-=t*k;
			s=max(0ll,s-t);
			q.push({a,0});//每个防御墙只差最后一个守卫时的情况
		}
		else//只差最后一个守卫,显然不用再加入优先队列了
		{
			s--;
			ans-=k;
		}
	}
	cout<<ans<<'\n';
	return 0;
}

感谢阅读。

posted @ 2025-10-30 16:16  Circle_Table  阅读(3)  评论(0)    收藏  举报