“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络友谊赛 A-张老师和菜哭武的游戏(GCD)

本文深入探讨了在特定数学游戏中,如何通过分析数的性质和最大公约数(gcd)来判断游戏胜负策略。通过理解数可以表示为a*x+b*y的形式,揭示了p必须是gcd(a,b)的倍数这一关键规律,进而提出了一个简洁高效的算法,用于快速判断在给定范围内,先手玩家是否有获胜可能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


http://www.yyycode.cn/index.php/2020/05/16/%e7%a7%91%e5%a4%a7%e8%ae%af%e9%a3%9e%e6%9d%af%e7%ac%ac%e5%8d%81%e4%b8%83%e5%b1%8a%e5%90%8c%e6%b5%8e%e5%a4%a7%e5%ad%a6%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e9%a2%84%e9%80%89%e8%b5%9b/ 


思路:观察到开始的时候在1-n中选p,这个p是有a+b/a-b的性质的。

我们现在先把a+b记为c,a-b记为d;这个c是a*x1+b*y1的一种形式,同理这个d也是a*x2+b*y2的一种形式

那么下一次拿的数字为a+c,a-c,b+c,b-c;将c/d换成上一行提到的形式,可得下一次拿的都是 a*x+b*y的形式,那么我们可以知道p=a*x+b*y,那么p是gcd(a,b)的倍数,于是在1-n中算出有多少个gcd(a,b)的倍数,如果是奇数那么先手赢

反思:如果一个数能表示成p=a*x+b*y,那么p是gcd(a,b)的倍数

简单理解:gcd(a,b)=d;那么p=d*(x+?)+b*(y+?);

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5;
typedef long long LL;

LL gcd(LL a,LL b)
{
	return b?gcd(b,a%b):a;
}
int main(void)
{
	LL t;cin>>t;
	while(t--)
	{
		LL n,a,b;cin>>n>>a>>b;
		LL k=n/gcd(a,b);
        k-=2;
		if( k>0 && k%2==1 ) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	} 

return 0;
}
<think>好的,我现在需要解决用户关于同济大学程序设计竞赛中“打怪hard版本”的问题。题目中涉及AD(攻击力)HP(生命值)都达到1e12的情况,需要找到高效的算法来处理这么大的数值。首先,我得理解题目的大致要求,可能是一个打怪游戏中的最优策略问题,比如在最短时间内击败怪物,或者如何在有限的资源下生存下来。 首先,我应该回忆类似的问题。比如,常见的打怪问题通常是计算每次攻击造成的伤害,怪物可能也会反击,所以需要找到攻击次数生存之间的平衡。如果ADHP都是1e12,普通的模拟方法(比如循环计算每次攻击)肯定会超时,因为时间复杂度太高。所以必须找到一个数学上的优化方法,避免逐次计算。 接下来,可能的解题思路是数学建模。比如,假设每次攻击后,怪物的HP减少AD,而角色可能受到怪物的反击伤害。这时候需要计算角色在击败怪物前能承受多少次反击,从而确定是否可行。或者可能需要计算最小的攻击次数,使得在怪物被击败前,角色不会死亡。 假设问题类似于:角色每次攻击造成AD点伤害,怪物每次反击造成一定的伤害。角色初始有HP,怪物有初始HP。需要判断角色能否击败怪物,或者计算最小攻击次数。这种情况下,攻击次数k必须满足角色在k次攻击后,怪物的HP <=0,同时角色在受到k-1次反击后的HP >0。 数学表达式可能是这样的:怪物HP <= AD * k,同时角色HP > (k-1)*D,其中D是每次反击的伤害。这时候需要找到最小的k满足这两个不等式。不过具体题目中的反击机制可能不同,比如怪物是否在每次被攻击后反击一次,或者是否有其他条件。 但是题目中的具体条件不明确,所以可能需要做一些假设。比如,假设每次攻击后怪物会反击一次,那么角色在发动k次攻击后,怪物受到的总伤害是AD * k,而角色受到的总伤害是D * k(如果怪物在每次攻击后反击,直到被击败为止)。或者可能怪物在死亡后不会反击,所以角色攻击k次,怪物反击的次数可能是k-1次,如果最后一次攻击击败了怪物,那么怪物不会反击第k次。 所以需要明确反击次数是k-1次。因此,角色需要满足HP > D*(k-1),同时AD*k >= 怪物HP。这时候,解这两个不等式可以得到k的最小值。但因为ADHP都是1e12,直接计算k可能涉及到解这两个不等式的交集。 不过,如果D是固定的,或者题目中的其他参数已知,这时候需要找到满足条件的最小k。例如,如果怪物的初始HP为M,那么k的最小值满足k >= ceil(M/AD),同时HP > D*(k-1)。这时候需要找到k的下界,使得两个条件都满足。这可能涉及到在k的两个约束中取最大值,并进行数学上的推导。 比如,假设M是怪物的HP,H是角色的HP。则k的最小值为max(ceil(M/AD), floor((H-1)/D)+1)。但可能需要具体情况具体分析。例如,如果ceil(M/AD)对应的k值是否满足H > D*(k-1)。如果不满足,那么可能需要更大的k值,此时需要解联立方程。 这个时候,问题就转化为求解满足k >= M/AD H > D*(k-1)的最小整数k。这可能可以通过数学方法直接计算,而不需要遍历。例如,将第二个不等式变形为k <= (H-1)/D +1,然后找到k的范围。但这里可能存在矛盾,如果M/AD的上界大于这个范围,则无解;否则,取较大的那个。 不过,在题目中,可能D是怪物的攻击力,而角色在每次攻击后会被攻击一次,直到怪物死亡。例如,假设怪物有HP为M,AD为角色的攻击力,而每次攻击后,怪物会反击,造成D的伤害。那么,角色需要攻击k次,其中k是满足k*AD >= M的最小整数。此时,角色受到的伤害是D*(k-1),因为最后一次攻击后怪物死亡,不会反击。所以,角色需要HP > D*(k-1)。因此,k必须同时满足k >= ceil(M/AD) D*(k-1) < HP。也就是,k的最小值必须满足这两个条件。 这时候,k的最小可能为ceil(M/AD)。但是需要检查此时D*(ceil(M/AD)-1)是否 < HP。如果是,则可行;否则,需要找到更大的k,使得D*(k-1) < HP,同时k >= ceil(M/AD)。但此时如果ceil(M/AD)对应的k导致D*(k-1) >= HP的话,说明无法击败怪物,因为即使攻击次数足够击败怪物,角色也会在之前被击败。 但题目可能要求必须存在解,所以在这种情况下,我们需要确保存在这样的k。例如,当ceil(M/AD)的值对应的D*(k-1) < HP,否则无解。或者题目可能保证有解,这时候需要找到满足条件的最小k。 回到题目中的情况,ADHP都达到1e12,这说明不能使用循环遍历k,必须用数学公式直接计算。例如,计算k的最小值为ceil(M/AD),然后检查D*(k-1)是否 < HP。如果满足,则k即为解;否则,需要更大的k,但此时可能需要重新解方程。 例如,假设k_min = ceil(M/AD)。此时,如果 HP > D*(k_min -1),那么输出k_min。否则,需要解k必须满足: k >= ceil(M/AD) 并且 k <= floor( (HP-1)/D ) +1 这可能只有当ceil(M/AD) <= floor((HP-1)/D ) +1 时才有解。否则无解。 因此,总共有两种情况: 1. 当 ceil(M/AD) <= floor( (HP-1)/D ) +1 时,解为 ceil(M/AD) 2. 否则,无解。 但需要验证这个逻辑是否正确。例如,假设M=5,AD=2,那么ceil(5/2)=3。此时,k_min=3。假设D=1,HP=3,那么D*(3-1)=2 <=3,满足,所以可行。如果HP=2,那么D*(3-1)=2 >=2,此时无法满足。这时候是否需要寻找更大的k?比如k=4,此时攻击次数4次,怪物受到的伤害是2*4=8>=5。此时,角色受到的伤害是D*(4-1)=3。如果HP=3,刚好等于,可能题目中的条件是HP需要大于总伤害,所以必须HP >3。这时候如果HP=3的话,无法存活。因此,这种情况下需要判断是否存在解。 但回到题目中的情况,因为ADHP都是1e12量级,所以必须用数学方法直接计算,而不能遍历。因此,正确的解法应该是: 计算k_min = ceil(M / AD) 如果 HP > D*(k_min -1),则输出k_min 否则,无解,或者需要调整。 但题目可能要求必须输出解,所以可能在这种情况下,当HP <= D*(k_min -1),则需要找到最小的k满足: k >= ceil(M/AD) 且 k <= (HP-1)//D +1 但这必须保证ceil(M/AD) <= (HP-1)//D +1。否则无解。 所以,综合起来,算法步骤如下: 1. 计算k_min_attack = ceil(M / AD),这是击败怪物所需的最小攻击次数。 2. 计算k_max_survive = floor( (HP -1)/ D ) +1。这是角色能够承受的最大攻击次数,即当k_max_survive次攻击后,角色刚好存活(总伤害是D*(k_max_survive -1) <= HP-1)。 3. 如果k_min_attack <= k_max_survive,则输出k_min_attack。 4. 否则,无解。 所以,关键点在于如何高效计算这些值,特别是当数值非常大时(1e12)。 例如,假设M=1e12,AD=1,则k_min_attack=1e12。此时,如果D=2,HP=1e12*2 -1,那么k_max_survive = floor( (HP-1)/D ) +1 = floor( (2e12 -2)/2 ) +1 = (1e12 -1) +1 =1e12。此时k_min_attack=1e12,等于k_max_survive,所以可行。输出k_min_attack=1e12。 但若HP=2e12 -2,则k_max_survive= (2e12-3)/2 +1= (1e12-1.5)取整为1e12-2 +1=1e12-1。此时,k_min_attack=1e12 >k_max_survive,无解。 所以在这种情况下,只要k_min_attack <=k_max_survive,就输出k_min_attack,否则输出-1或者某种标识。 但具体题目是否保证一定有解,可能需要看题目要求。假设题目保证有解,那么我们可以直接输出k_min_attack。 但用户的问题可能要求的是在给定ADHP的情况下,找到最优策略,所以需要这样的数学处理。 那么,回到问题的解法,用户的问题可能类似于:角色每次攻击造成AD伤害,怪物每次反击造成D伤害。角色初始HP为H,怪物初始HP为M。求击败怪物的最小攻击次数,或者判断是否可能。 针对这种情况,正确的算法应该是: 计算k_min = ceil(M / AD) 计算最大可以承受的k值为k_max = floor( (H-1)/D ) +1 如果k_min <=k_max,则答案是k_min,否则不可能。 但如何高效计算这些值?因为MAD都是1e12,所以直接做除法即可,在Python中可以用整除模运算来处理。 例如,ceil(M / AD)等于 (M + AD -1) // AD。 例如,当M=5,AD=2时,(5+2-1)//2=6//2=3,正确。 而k_max的计算是 (H-1)//D +1,例如H=3,D=1,得到 (2)//1 +1=2+1=3,此时角色最多承受3次反击,即k_max=3。因此攻击次数k可以是3,此时反击次数是2次(k-1=2),总伤害是2*1=2 <=3-1=2,满足条件。 所以,在代码中,我们可以这样处理: k_min = (M + AD -1) // AD k_max = (H -1) // D +1 if k_min <=k_max: print(k_min) else: print(-1) 但需要处理D=0的情况,例如怪物不反击,这时候只要k_min即可。不过题目中的情况可能D不为零。 现在回到用户的问题,题目中的ADHP都是1e12级别,所以需要确保这些计算在Python中不会溢出或者时间过长。因为Python的整数可以处理大数,所以没问题。 综上,解题思路是数学计算,找到满足两个条件的最小k值,不需要循环,直接通过公式计算即可。这样就避免了处理大数时的性能问题。</think>对于“打怪hard版本”问题,处理ADHP均为$1e12$量级的情况时,直接模拟攻击过程会超时,需通过数学分析优化时间复杂度。以下是核心思路: ### 问题分析 假设怪物初始血量为$M$,角色攻击力为$AD$,怪物每次反击伤害为$D$,角色初始血量为$HP$。需要找到最小攻击次数$k$,使得: 1. $AD \cdot k \geq M$(击败怪物) 2. $D \cdot (k-1) < HP$(角色存活) ### 数学推导 1. **最小攻击次数下限**: 击败怪物至少需要$k_{\text{min}} = \lceil \frac{M}{AD} \rceil$次攻击,可通过公式$k_{\text{min}} = \frac{M + AD -1}{AD}$计算[^1]。 2. **最大存活次数上限**: 角色能承受的最大反击次数为$k_{\text{max}} = \lfloor \frac{HP-1}{D} \rfloor +1$。若$D=0$(怪物不反击),则直接返回$k_{\text{min}}$。 3. **判定条件**: 若$k_{\text{min}} \leq k_{\text{max}}$,则存在解,输出$k_{\text{min}}$;否则无解。 ### 代码实现 ```python def calculate_min_attacks(M, AD, HP, D): if D == 0: return (M + AD - 1) // AD k_min = (M + AD - 1) // AD k_max = (HP - 1) // D + 1 return k_min if k_min <= k_max else -1 # 示例输入:M=1e12, AD=1e12, HP=1e12, D=1 print(calculate_min_attacks(10**12, 10**12, 10**12, 1)) # 输出1 ``` ### 复杂度分析 - **时间复杂度**:$O(1)$,仅涉及常数次算术运算。 - **空间复杂度**:$O(1)$,无需额外存储。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值