题目大意:
Monocarp 又在玩电脑游戏了。他是一个巫师学徒,只知道一个咒语。幸运的是,这个法术可以伤害怪物。 他当前所在的级别包含 n 个怪物。他们中的第 i 个在关卡开始后出现 ki 秒,并且有 hi 生命值。作为附加约束,对于所有 1≤i≤n,hi≤ki。所有的ki都不一样。 Monocarp 可以在关卡开始后正整数秒的时刻施法:1,2,3,... 法术的伤害计算如下。如果他在前一秒没有施法,则伤害为1。否则,让前一秒的伤害为x。然后他可以选择伤害为 x+1 或 1。法术使用法力:施展伤害为 x 的法术使用 x 法力。法力不会再生。 为了杀死第 i 个怪物,Monocarp 必须在怪物出现的确切时刻施放一个伤害至少为 hi 的法术,即 ki。 请注意,即使当前秒没有怪物,Monocarp 也可以施法。 施法所需的法力值是所有施法法术的法力使用量之和。计算 Monocarp 杀死所有怪物所需的最少法力值。 可以证明,在问题的约束下,总是有可能杀死所有的怪物。
输入
第一行包含一个整数 t (1≤t≤10^4)——测试用例的数量。
测试用例的第一行包含一个整数 n (1≤n≤100)——关卡中怪物的数量。
测试用例的第二行包含 n 个整数 k1<k2<⋯<kn (1≤ki≤10^9) — 第 i 个怪物从开始出现的秒数。
所有的 ki 都是不同的,ki 是按递增顺序提供的。 测试用例的第三行包含 n 个整数 h1,h2,…,hn (1≤hi≤ki≤10^9) — 第 i 个怪物的健康状况。
所有测试用例的 n 总和不超过 10^4。
输出
对于每个测试用例,打印一个整数——Monocarp 杀死所有怪物所需的最少法力值。
(以上翻译来自谷歌)
题解:
既然肯定可以成立,我们就可以放心大胆的开做了。
首先,我们读了题目会发现伤害至少是hi,那么我们要造成的伤害肯定是要大于这个,因此如果我们前面遇上比如3秒开始蓄力就能杀死的敌人和现在这个要从第一秒开始蓄力才能打死的敌人,为了可以全部打死,我们肯定要从第一秒开始蓄力。那么我们明确了一个观点,后面会影响前面。那么我们对于这个问题的解决方法就是:从后面开始做。
那么我们只需要做到两件事:第一件事情就是如果遇到上一个时间和当前这个时间之内能蓄力打的死的,我们就正好蓄力在这个时刻以这个力量打死。
第二件事是如果上个时间和当前这个时间之内不能打死的,我们要先找到它需要蓄力的最早时间,我们就要覆盖住这个范围,然后往前推进(往前推进的意思是如果我们发现当前的这个时间比需要蓄力的最早时间晚,我们就对它进行更新,看看能不能找出需要更早蓄力的时间,知道找不出)。
以下就是代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
long long int k,h;
}a[200];
long long int sum(long long int n){
return n*(n+1)/2;
}
int main(){
int t;
scanf("%d",&t);
int cnt=0;
while(t--){
int n;
cnt++;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].k);//时间
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].h);//血量
int j;
long long int res=1e9;
long long ans=0;
for(int i=n;i>=1;i--){
if(a[i].h<a[i].k-a[i-1].k+1){//时间够
res=a[i-1].k;
ans+=sum(a[i].h);
}
else{
res=a[i].k-a[i].h+1;//找到它的最前界
j=i-1;
while(a[j].k>=res&&j>0){
res=min(a[j].k-a[j].h+1,res);
j--;
}
int u=i;
i=j+1;
ans+=sum(a[u].k-res+1);
}
}
printf("%lld\n",ans);
}
}