C. Monsters And Spells(区间合并)

Problem - C - Codeforces

 Monocarp又在玩电脑游戏了。他是个巫师学徒,只会一个咒语。幸运的是,这个法术可以伤害怪物。他当前所在的关卡包含n个怪物。第i个在关卡开始后k秒出现,并拥有h个生命值点。作为一个附加约束,hi < ki对于所有1 <i< n。所有ki都是不同的。Monocarp可以在关卡开始后的正整数秒量的时刻施放法术:1,2,3,…法术伤害的计算方法如下。如果他在前一秒没有施法,伤害为1。否则,就让前一秒的损失消失吧。然后他可以选择伤害为æ + 1或1。法术使用法力值:施放伤害为A的法术需要x法力值。法力值不会回复。要杀死第i个怪物,Monocarp必须在怪物出现的那一刻施放至少h点伤害的法术,也就是ki注意,即使当前秒内没有怪物,单果也可以施放该法术。施法所需的法力值是所有施法法术的法力值之和。计算Monocarp杀死所有怪物所需的最小法力值。我们可以看到,在问题的限制条件下,玩家总是有可能杀死所有怪物。输入第一行包含一个整数t (1 < t < 104)——测试用例的数量。测试用例的第一行包含一个整数n (1 < n < 100)——关卡中怪物的数量。测试用例的第二行包含n个整数ki < k2 <…< kn (1 < ki < 10°)-从第i个怪物出现的开始的秒数。所有的k都是不同的,k是按递增顺序提供的。测试用例的第三行包含n个整数h1, h2,.., hn (1 < hi < k;< 10°)-第i个怪物的生命值。所有测试用例的n和不超过104。输出对于每个测试用例,打印一个整数——Monocarp杀死所有怪物所需的最小法力值。

Example

input

Copy

 

3

1

6

4

2

4 5

2 2

3

5 7 9

2 1 2

output

Copy

10
6
7

请注意在这个例子的第一个测试案例中,Monocarp可以在开始后3、4、5和6秒施放伤害分别为1、2、3和4的法术。6秒时造成的伤害为4,这确实大于或等于出现的怪物的生命值。在这个例子的第二个测试用例中,Monocarp可以在开始时施放3、4和5秒的法术,伤害分别为1、2和3。在这个例子的第三个测试案例中,Monocarp可以在开始时施放4,5,7,8,9秒的法术,伤害分别为1,2,1,1和2。

题解:

如果要让消耗最小,最好是法术伤害在ki时刚好等于hi,这样我们知道了每个区间最优应该从哪开始

ki - hi + 1 ~ ki

(好了,本题结束,开玩笑的)

我们相当于的到了n个区间,如果没有重复的直接计算即可,

那对于有重复的区间该怎么算呢

我们先对右边从小到大排序,得到的区间大概是这样的

如果区间直间有覆盖肯定是要从最左边的区间,计算的最右边的区间,这样才能满足后面被覆盖的区间,

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
using namespace std;
//#define int long long
const int N = 2e5 + 10;
typedef pair<int, int> PII;
typedef long long ll;
int k[N];
int h[N];
struct node
{
	int l,r;
}a[N];
bool cmp(node a,node b)
{
	return a.l < b.l; 
}
void solve() 
{
	int n;
	scanf("%d",&n);
	ll ans = 0;
	for(int i = 1;i <= n;i++)
	{
		scanf("%d",&k[i]);
	}
	for(int i = 1;i <= n;i++)
	{
		scanf("%d",&h[i]);
		a[i].l = k[i] - h[i] + 1;
		a[i].r = k[i];
	}
	sort(a + 1,a + 1 + n,cmp);
	int s = a[1].l,e = a[1].r;
	for(int i = 2;i <= n;i++)
	{
		if(a[i].l <= e)
		{
			s = min(s,a[i].l);
			e = max(e,a[i].r);
		}
		else
		{
			ll len = e - s + 1;
			ans += len*(len + 1)/2;
			s = a[i].l;
			e = a[i].r;
		}
	}
	ll len = e - s + 1;
	ans += len*(len + 1)/2;
	cout << ans <<"\n";
}

//1 2 4
signed main() 
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
scanf("%d",&t);
	while (t--) 
	{
		solve();
	}
}
//1 1 1 0 1

//1 1 1 0 1
//1 1 1 0 1
//1 1 1 0 1
//0 1 1 1 1
//0 1 1 1 1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值