题解: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;
}
感谢阅读。
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/19177431

浙公网安备 33010602011771号