UPC 2021个人训练赛13场K:勇士斗恶龙

题目描述
小 X 穿越到了异世界,国王命令他招揽勇士,杀死恶龙,救回公主。
异世界是高度数据化的。恶龙有一个攻击力 ATK,一个生命值 HP。类似的,每个勇士也有一个攻击力 Ai,一个生命值 Hi。
战斗是回合制的,并且每次只能由一个勇士和恶龙单挑。战斗中,每个回合恶龙的生命值会减去这个勇士的攻击力,这个勇士的生命值会减去恶龙的攻击力。
如果回合结束的时候恶龙的生命值小于等于 0,那么恶龙就被杀死了;如果这个勇士的生命值小于等于 0,那么这个勇士就被击败了,需要换上另一个勇士继续战斗。当然,如果恶龙还没有被杀死,勇士却全部被击败了,那么这场战役就彻底失败了。
不过聪明的小 X 安排了一个特殊的战术:在一名勇士被击败后立刻让另一名勇士发起攻击,这样恶龙在勇士们的车轮战术下疲于招架,受到第二个勇士的伤害变为两倍,受到第三个勇士的伤害变为三倍……以此类推。
现在一共有 n 名勇士报名,小 X 想问问你,如果合理安排勇士出战的顺序,最少要招揽多少名勇士才能杀死恶龙?

输入
第一行为一个正整数 n,表示一共有 n 名勇士报名。
第二行两个正整数 ATK 和 HP 表示恶龙的攻击力和生命值。
接下来共有 n 行,每行两个正整数 Ai 和 Hi 表示这名勇士的攻击力和生命值。

输出
输出一个整数,表示最少要招揽多少名勇士才能杀死恶龙。
如果不可能杀死恶龙,输出”Fail”。

样例输入
2
1 9
2 2
1 1

样例输出
2

样例解释
样例解释
两名勇士都招揽。先派出 2 号勇士
第一回合,恶龙生命值变为 8,勇士生命值变为 0。勇士被击败
紧接着派出 1 号勇士
第二回合,恶龙生命值变为 4(两倍伤害),勇士生命值变为 1
第三回合,恶龙生命值变为 0,勇士生命值变为 0。恶龙被杀死
勇士虽然也被击败了,但恶龙已经死了,所以还是胜利了!
数据范围
本题共有 10 个测试点,每个测试点 15 分
对于测试点 1-4 :n<=5,ATK,Hi,Ai<=10,HP<=100
对于测试点 5-7 :n<=1000,ATK,Hi,Ai<=1000,HP<=10^9
对于测试点 8-10 :n<=105,ATK,Hi,Ai<=106,HP<=10^18

思路历程

我最开始看到这个题的时候,第一反应就将所有勇士按照伤害的大小进行排序,伤害低的放前面,伤害高的放后面。这样就可以保证所有勇士的造成伤害最大化。更容易击杀恶龙,但是这只是造成伤害最大的情况,题目要求的是求出能杀死恶龙的最少人数。

但是考虑到这种情况:
假如勇士的队伍里有一个非常NB的勇士,那么根本不需要其他小喽喽给他做铺垫,他自己就可以独自解决饿龙了。

所以我改变了一下思路:
我将伤害高的排在前面,伤害低的排在后面,然后从左向右选人并且出战。试试能不能用这种方法把恶龙秒了!就不需要那么多人了!

但是我发现了一组样例又能hack掉我这样的计算方式
hack 样例:
假如恶龙 攻击力 1 生命值 25
3名勇士: 10 1
5 1
4 1
如果按照上述错误的排序,需要3个人才能解决
但是实际上只需要两个人。
这样的方法会使总体的造成伤害过低,遇到高生命值的恶龙反倒需要更多人

正确的思路(避免看废话)

那有什么办法能让伤害又高,上阵的人又少呢?
让勇者们按照实际能造成伤害的高低排序

然后从能造成伤害高的开始一个一个选。
先选出来的勇者后上阵 。(保证总伤害最高)

一个勇者能造成的伤害=勇者输出的次数*勇者的攻击力(没经过新战术提升的情况下)

AC代码:

#include<bits/stdc++.h>
using namespace std;
struct Stu
{
	long long hp;//生命值 ! 
	long long gong;// 攻击力! 
	long long shiji;//实际上能造成伤害的多少! 
}stu[100001];
bool cmp(Stu x,Stu y)
{
	return x.shiji<y.shiji;
}
int main()
{
	long long n;
	cin>>n;
	long long  bossgong;
	long long  bosshp;
	cin>>bossgong>>bosshp;
	for(int i=1;i<=n;i++)
	{
		cin>>stu[i].gong;
		cin>>stu[i].hp;
		int h=stu[i].hp/bossgong;
		int g=stu[i].hp%bossgong;
		if(g!=0)
		h++;
		stu[i].shiji=h*stu[i].gong;
	}
	sort(stu+1,stu+1+n,cmp);
	//for(int i=1;i<=n;i++)
//	{
	//	cout<<stu[i].gong<<" "<<stu[i].hp<<" "<<stu[i].shiji<<endl;
	//}
	long long sum=0;
	long long ans;
	long long num=0;
	long long temp=0;
	int flag=0;
	for(int u=n;u>=1;u--)
	{
		sum=sum+temp;
		sum+=stu[u].shiji;
		temp+=stu[u].shiji;
		//cout<<sum<<endl;
		num++;
		if(sum>=bosshp)
		{
			ans=num;
			flag=1;
			break;
		}
	}
	if(flag==1)
	cout<<ans;
	else
	printf("Fail");
	return 0;
}

本代码详细的模拟过程(也是废话)
样例
:假如恶龙 攻击力 1 生命值 25
3名勇士: 10 1
5 1
4 1
排序之后:4 1 5 1 10 1
开始选人:10 1 →造成伤害 10点+0点+0点=10点 (恶龙没死,继续向左选人)

5 1→造成伤害:5点+10点+10点(由于先选的人后上阵,上一个勇者的攻击提升10点) =25点!

4 1 →造成伤害: 4点+25点+15点= 44点!

所以根据上述模拟可知,2个人 就可以把恶龙杀死了!
并且这种情况是伤害最多情况下的选人最少,符合条件!

其中:4是本回合新选的勇士的伤害,25是上次选人的伤害
15是之前选过的所有勇士伤害的提升值!
加起来就是勇士们的总伤害了!

2021/5/23

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值