赛后题解——问题 B: 挑战

问题 B: 挑战
题目描述

所谓真实,不过是我们在意识中的臆想罢了。真实可以是虚假的。
这是Kanna从昏迷中悠悠醒转时,隐隐听到的声音。
Kanna是一条威猛的龙。但是她在心中走丢了。
静谧的夜,火光映着木柴噼啪作响。
Kanna略显呆滞地坐在火堆旁。和身旁的老者一起,脸庞被火焰映得明亮。
“小姑娘,你怎么来这里的?这里这么危险。”老人的声音响起,仿佛被历史长河淘洗过般沙哑。
Kanna埋着头,仿佛做错了什么似的。
“我不知道。”
经过了解,Kanna发现她来到了一个奇怪的星球上。
这里最有特色的,是战斗方式。
具体来说,这里因为一些极为特殊的原因,战斗是严格的回合制。即,战斗的两方轮流使用技能。
每一个技能使用时,都会产生两种效果:给对方强制扣除A点血量,给自己加上B点血量。每个人只有初始血量S,但是血量没有上限。
每个人只有一个技能,每次战斗一旦开始,就会一直进行到双方有任意一方血量小于等于零。
Kanna决定新的生活,从战斗开始。
现在Kanna来到某道馆里踢馆,遇到了n个对手。因为Kanna过于威猛,他的对手们决定每一回合都让Kanna先行动。
Kanna会从第1个到第n个,依次挑战这些对手。每回战斗结束之后,她都会把自己的血量回满再开始下一场。哪怕自己血条被清空了,她也能在战斗结束后自己复活。也就是说,Kanna与每个人之间的挑战均是独立的。
对于第i个对手,他的初始血量为S_i,技能每次扣除对方A_i点血,给自己回复B_i点血。
Kanna的血量为S_0,技能每次扣除对方A_0点血,给自己回复B_0点血。
现在Kanna得知了所有这些信息。她想知道,最终她能打败多少人。
我们称Kanna打败了一个人,当且仅当战斗可以结束,且战斗结束时,Kanna剩余血量大于零,而对方剩余血量小于等于零。

输入

第一行一个正整数n,表示对手个数(1<=n<=1000)
第2到n+2行,每行三个正整数。
第i行的三个数分别为Si,Ai,Bi。

输出

一行一个正整数,表示Kanna能打败的人数。

样例输入

3
10 2 2
2 100 100
13 3 0
3 0 100

样例输出

2

提示

扫描二维码关注公众号,回复: 11240368 查看本文章

我们设S=max(Si),A=max(Ai),B=max(Bi)
对于80%的数据,1<=S,A,B<=1000
对于100%的数据,1<=S,A,B<=2e9,1<=n<=1000

  • 题意:就是寻找到可以打败的人数,即在对方的血方小于零的时候,我方的血量还是正的。
    并且有一个条件就是:每个人只有一个技能,每次战斗一旦开始,就会一直进行到双方有任意一方血量小于等于零。所以不可能存在都小于等于零的情况。

  • 分析:
    在这里插入图片描述
    x y z表示我方,a b c表示敌方。
    讨论一下可以获胜的情况就OK了。
    情况一: y > a 在第一次攻击时敌方的血量就小于零了。
    情况二 : y > c && z >= b 这个特判的含义就是在每一轮中我方的回血量大于等于零,而对方的回血量是小于零的,这种肯定可以获胜。
    情况三:y > c && b > z 这种情况比较复杂,必须算出敌我双方能够抗的次数。
    我方的血量:x + z - b + z - b + … + z - b 当我方的血量小于等于零时,最后一次肯定是受伤,而不是回复,所以设扛了k1轮的伤害,即:x + k1 * (z - b) <= 0 (k1一定要上取整,并且还要乘二,因为一轮中分为我方攻击和我方受伤两次,模拟一遍就懂!)
    敌方的血量: a - y + c - y +c … -y 当敌方的血量小于等于零时,最后一次也是受伤,不同在于敌方在攻击前已经受伤,所以把a - y看成敌方的血量计算,所以设在第一次受伤后扛了k2轮的伤害,即:a - y + k2 * (c - y) <= 0 (k2也要上取整,并且乘以二,别忘了加上第一次受伤的次数)

  • 注意:上述的一轮是来回,即:我打你一下,你打我一下。

上代码!!!

//优化
#pragma GCC optimize(2)
//C
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
//C++
//#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<istream>
#include<iomanip>
#include<cstdio>
#include<stack>
#include<string>
#include<vector>
#include<cmath>
#include<queue> 
#include<map>
#include<set>
//宏定义
#define N 2500
#define DoIdo main
//#define scanf scanf_s
#define it set<ll>::iterator
//定义+命名空间
typedef long long ll;
typedef unsigned long long ull;
const int mod = 55555;
const int INF = 2e9 + 10;
const int maxn = 2e6 + 10;
using namespace std;
//全局变量
//函数区
ll max(ll a, ll b) { return a > b ? a : b; }
ll min(ll a, ll b) { return a < b ? a : b; }
//主函数
int DoIdo() {

	//ios::sync_with_stdio(false);
	ll n, x, y, z;
	cin >> n >> x >> y >> z;

	ll ans = 0;
	for (int i = 1; i <= n; i++) {
		ll a, b, c;
		cin >> a >> b >> c;
		if (y >= a) ans++;
		else if (y > c && z >= b) ans++;
		else if (y > c && b > z) {
			ll k1 = (x + b - z - 1) / (b - z);
			k1 *= 2;
			a -= y;
			ll k2 = (a + y - c - 1) / (y - c);
			k2 = k2 * 2 + 1;
			if (k1 >= k2) ans++;
		}
	}

	cout << ans << endl;
	return 0;
}
//分割线---------------------------------QWQ
/*

血  伤  回复
x    y    z
a    b    c


*/

/*

f(n) = ln(n) + C + 1 / 2 * n
double C = 0.57721566490153286060651209;
*/

猜你喜欢

转载自blog.csdn.net/qq_45739057/article/details/105577690