题目链接:https://ac.nowcoder.com/acm/contest/1111/D
题意理解:
有两种法术攻击:射击(-2 HP)和冰箭数( -3 HP)。
给你n个仆从的HP(h(i)),求 f(0),f(1),f(2)......f(m)。
f(i)表示杀死所有仆从的最小冰箭数,且可用射击次数为i。
题解:
优先队列贪心做,代码上有详细解释。
#include<iostream>
#include<queue>
using namespace std;
const int maxn=1e5+7;
const int mod=1e9+7;
struct Point{
int x;
bool friend operator < (Point a,Point b){//贪心的做法,先选余数大的,这样用射击攻击后hp变成能被3整除的概率高,尽可能保证冰箭数的利用率高,
return a.x%3==b.x%3?a.x<b.x:a.x%3<b.x%3;
}
}p;
priority_queue<Point> q;
int solve(int x){//求杀死当前服从所需的最小冰箭数
int ans=0;
if(x%3!=0) ans++;
ans+=x/3;
return ans;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
while(!q.empty()) q.pop();
long long sum=0;//sum初始存储杀死所有仆从的最小冰箭数
for(int i=1;i<=n;i++){
scanf("%d",&p.x);
sum+=solve(p.x);
q.push(p);
}
long long temp=sum;//即f(0)的情况
while(m--&&!q.empty()){
Point t=q.top();
q.pop();
// printf("%d\n",t.x);
sum-=solve(t.x);//减去杀死当前仆从的最小冰箭数
t.x-=2;//使用一次射击攻击
if(t.x>0){//仆从仍未死亡
sum+=solve(t.x);//重新加上被射击攻击后杀死仆从的所需冰箭数
q.push(t);//继续入优先队列
}
temp=(temp+sum)%mod;//每用一次射击都加到temp上,类似求f(1),f(2)..f(n)的过程
// printf("%lld\n",temp);
}
printf("%lld\n",temp%mod);
}
return 0;
}