Educational Codeforces Round 121 1626C Monsters And Spells

题目描述(传送门

在这里插入图片描述

题目翻译:

Monocarp正在玩电脑游戏,他现在是一个巫师学徒,只会一个技能。幸运地是,这个技能可以打败怪兽。当前有n个怪兽,第i个怪兽在第ki 秒出现,且该怪兽的生命值为hi。其中hi ≤ ki,且ki互不相同。
Monocarp可以在整秒时刻(从1开始,1,2,3,…)发出技能,技能的伤害为:如果前一秒他没有发出技能,则此时技能的伤害值为1;如果前一秒技能的伤害值为x,则他可以选择此时技能的伤害值为x+1或1。使用一个伤害值为x的技能,将消耗x个mana,并且mana不可再生。
为了杀死第i个怪兽,Monocarp必须在ki时刻,发出技能,并且技能的伤害值至少为hi
Monocarp可以在没有怪兽出现的时刻发出技能。
计算杀死所有的怪兽,至少需要消耗多少个mana。
题目保证可以杀死所有的怪兽。

解题思路:

为了杀死在第ki秒出现的生命值为hi的怪兽,Monocarp需要提前做好准备,使其技能的伤害值在第ki秒时至少为hi,用直方图来表示技能在不同时刻的伤害值,横向表示时间,纵向表示伤害值大小。
比如,假设全程只有一个生命值为5的怪兽,其在第6秒出现,则Monocarp最晚需要从第2秒开始,积累技能的伤害值,这样才能使技能的伤害值在第6秒达到5,并且消耗的mana也最少。
在这里插入图片描述
设怪兽的生命值为hi,则消耗的mana=(hi+1)*hi/2,可以发现消耗的mana可由该怪兽的生命值直接计算得出。
但题目没有这么简单,如果在第2秒到第6秒之间出现了其他怪兽,则可能产生影响。
比如在第4秒出现了一个生命值为4的怪兽
在这里插入图片描述
则为了杀死这两个怪兽,我们需要将生命值整体增加,变成这样
在这里插入图片描述
这时候mana的消耗量=(6+1)*6/2,发现这里的值6并不是某个怪兽的生命值了,而是由怪兽的生命值经过增加得到的。设最高蓝柱的高度为height,由height可以直接计算出消耗的mana量,height最开始是某个怪兽的生命值,并且随着其他怪兽的出现,height可能会相应地增大。就上面的例子而言,height的增值为4-3=1(注意看技能伤害值在第4秒的变化)。

而如果出现的怪兽的生命值小于等于当前时刻技能的伤害值,则height不发生改变。比如在第2秒出现一个生命值为1的怪兽:
在这里插入图片描述
可以发现,当前的生命值就足以消灭该怪兽。
至此,我们可以得出代码实现的思路,根据怪兽出现的时间,从后往前遍历,将height的初始值设为最后一个怪兽的生命值,再判断在当前蓝色阶梯区域内是否有其它怪兽,并比较其生命力与对应时刻技能的伤害值,若其生命力大于技能的伤害值,则增大height,此时蓝色阶梯区域也会相应地扩大。直到将蓝色阶梯区域内的怪兽都遍历结束,则可以计算出这一部分的mana消耗量,再继续遍历下一个怪兽。

代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 10010
#define INF 0x7fffffff
using namespace std;
int main(){
//	freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
    cin.tie(0);
	long long k[N],h[N],sum;
	int t,n,cur;
	cin>>t;
	while(t--){
		cin>>n;
		sum=0;
		for(int i=1;i<=n;i++) cin>>k[i];
		for(int i=1;i<=n;i++) cin>>h[i];
		//这里用某个怪兽的生命值h[cur]保存height,因为height会发生变化,所以h[cur]也会变化,但不会影响结果
		cur=n;
		for(int i=n-1;i>=1;i--){
			if(k[cur]-h[cur]<=k[i]-h[i]){//表示当前技能的伤害值足以消灭该怪兽
				continue;
			}else if(k[cur]-h[cur]<k[i]){//增加height
				h[cur]+=(h[i]-h[cur]-k[i]+k[cur]);
			}else{//表示蓝色阶梯区域内的怪兽都遍历完了,计算这部分的mana值
				sum+=(1+h[cur])*h[cur]/2;
				cur=i;
			}
		}
		sum+=(1+h[cur])*h[cur]/2;
		cout<<sum<<endl;
	}
	return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值