2021安徽省大学生程序设计竞赛:D:持续攻击

题目描述:

血魔遇到了N个敌人。初始血魔生命值为M,每秒钟血魔的生命值会减少1。如果血魔的生命值变为0,血魔会立刻消失,但在此之前他可以击杀敌人来恢复生命值。对于第i个敌人需要攻击Ti次才能杀死,血魔每秒钟可以攻击一次,每秒钟血魔可以攻击任意一个敌人,并且每次攻击可以同时击中任意多个敌人。敌人一共有K种类型,对于每种类型的敌人,血魔最多只能杀死一个。血魔在进行过所有攻击后,他可以立刻恢复他所杀死敌人的最小生命值,在恢复过后不能再继续进行攻击(如果血魔生命值变为0的瞬间恢复生命值,血魔不会死亡)。现在血魔想知道,他是否能杀死K个敌人,如果能的话,那么杀死K个敌人后,生命值最高能为多少?

输入说明:

第一行3个整数N,M,K,分别表示敌人数量,血魔初始的生命值,敌人类型数。

接下来N行,每行三个整数Hi,Ti,Ci,分别表示第i个敌人的生命值,需要攻击的次数和类型。

1 <= Ci <= K <= N <= 105

1 <= Hi,Ti,M <= 109

保证每种类型的敌人至少有一个。

输出说明:

如果不能杀死K个敌人输出-1,否则输出生命值最大值。

输入样例:

样例1

2 5 2

1 2 2

4 5 1

样例2:

5 4 2

4 2 1

1 1 1

4 1 1

3 2 2

1 1 2

样例3:

3 5 3

5 2 1

1 6 2

3 2 3

输出样例:

样例1:

1

样例2:

5

样例3:

-1

解题思路:

本题对时间复杂度的要求比较高,我们要杀死K个敌人,要取可以消灭的每种类型中的血量最大值。 题目告诉我们,杀死K个敌人后,我们可以吸收杀死的敌人的最小生命值

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
typedef long long ll;
int n,m,k;
struct node{
	int h,t,c;
};
inline bool cmp(node x,node y){
	return x.t<y.t;
}
void slove(){
	cin>>n>>m>>k;
	vector<node>a(n);
	for(auto &[h,t,c]:a)cin>>h>>t>>c,c--;
	sort(a.begin(),a.end(),cmp);
	vector<int>mx(k,0);
	priority_queue<pii,vector<pii>,greater<pii> >q;//从小到大 
	int ans=0,cnt=k;
	for(const auto &[h,t,c]:a){
		if(t>m)
		    break;
		int mn=1e9;
		if(h>mx[c]){
			q.push({h,c});
			if(mx[c]==0)
			    cnt--;
			mx[c]=h;
		}
		while(q.size()){
			auto [hh,cc]=q.top();
			if(mx[cc]>hh)
			    q.pop();
			else{
				mn=hh;
				break;
			}
		}
		if(!cnt){
			ans=max(ans,m-t+mn);
		}
	}
	if(!cnt)
    	cout<<ans<<endl;
	else
    	cout<<-1<<endl;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	slove();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值