来自DEEPSEEK
2025-02-09 14:38:11
发布于:广东
嗯,我得仔细看看这个问题。题目大意是说,玩家驾驶飞船经过n个星球,每个星球可能是资源型或者维修型。每次可以选择开采或者维修,这会影响到钻头的能力值p,进而影响后续的收入或支出。我们的目标是在这n个星球中选择操作,使得最终的收益最大化。要注意的是,金钱可以透支,所以可能需要考虑长期的影响。
首先,输入的第一行给出n、k、c、w,其中n是星球数目,k是开采后的损耗百分比,c是维修后的修复百分比,w是钻头的初始能力值。接下来的n行,每行给出type和x,type是1或2,分别代表资源型和维修型。资源型选择开采的话,得到a_ip的钱,之后p变为p(1-0.01k);维修型选择维修的话,支付b_ip的钱,之后p变为p(1+0.01c)。问题是要选择每一步是否进行操作,使得总收益最大。
那,怎么处理这样的问题呢?因为每一步的选择会影响后面的所有操作,所以动态规划可能是一个思路。但直接按照顺序处理的话,状态可能很难表示,因为p的值会不断变化,而且可能有很多不同的状态。这时候需要考虑是否有可以优化的方式,或者有没有递推的规律。
比如,假设我们知道在某个位置i之后的操作的最优解,那么对于i处的选择,我们可以根据后续的p的变化来逆推。这可能是一个逆序动态规划的思路。比如,从最后一个星球开始倒推,每一步计算当前状态下的最优选择,从而避免记录所有的可能p值的变化。
举个例子,假设在i+1到n的最优解已经计算好了,那么对于第i个星球的选择,我们需要考虑是否进行操作,以及操作后的p变化对后续的影响。这时候,可能可以将状态表示为某种系数,比如,当前的总收益可以表示为某个关于当前p的线性函数。例如,总收益可以分解为当前操作带来的收益,加上后续所有操作的收益总和。而后续的收益总和可能与当前的p有关,因为后续的每一步的p都是基于前面的操作变化的。
比如,假设在某个状态i,当前的p是某个值,那么之后的操作的总收益可能等于某个系数乘以当前的p,再加上另一个常数。或者,可能存在这样的递推关系。例如,如果我们能找到一个函数,表示从第i个星球开始的最优总收益,那么这个函数可能可以表示为p的线性函数,即a_i * p + b_i。然后,我们可以通过逆序的方式逐步推导每个位置的a_i和b_i。
假设我们从后往前考虑每个星球。对于每个星球i,我们有选择操作或者不操作两种情况。我们需要比较这两种情况下的总收益,取较大的那个。而总收益的计算需要考虑到当前操作对后续的影响,也就是p的变化。
比如,当处理到第i个星球时,假设后面的最优收益是f[i+1] = a_{i+1} * p_{i+1} + b_{i+1}。那么,当前星球i的选择会影响p的变化,从而影响后续的收益。
举个例子,假设当前是资源型星球,那么如果选择开采,那么当前获得的收益是a_i * p,然后p变为p*(1-0.01k)。那么,后续的收益就是a_{i+1} * (p*(1-0.01k)) + b_{i+1}。总收益为a_ip + a_{i+1} * p(1-0.01k) + b_{i+1}。或者,或者,可能这里的函数形式需要更仔细的处理。
或者,可能更一般地说,假设在处理完i+1到n的星球之后,得到的最优收益函数是fi+1 = a_{i+1} * p + b_{i+1}。那么,对于当前的星球i,我们需要比较两种情况下的总收益:是否进行操作。
比如,对于资源型星球i:
如果选择开采,则当前收益为a_i * p,然后p变为p*(1 - 0.01k)。后续的收益是f[i+1](p*(1 - 0.01k))。所以总收益是a_ip + a_{i+1} * p(1 - 0.01k) + b_{i+1}。
如果不选择开采,那么当前收益是0,p不变,后续的收益是f[i+1}(p)。总收益是0 + a_{i+1} * p + b_{i+1}。
所以,对于资源型星球i来说,应该选择两种情况中较大的那个。因此,总收益的最大值为max(a_i*p + (1-0.01k)*a_{i+1} *p + ... , a_{i+1} *p + ... )。但这里的表达式可能需要重新整理,找出系数a_i和b_i的递推关系。
或者,可能更简单的方式是,将当前的总收益函数表示为f[i}(p) = max{操作后的收益,不操作的收益}。而这里的操作后的收益可以转化为关于p的线性函数。比如:
对于资源型i:
如果选择开采,总收益是a_ip + f[i+1}(p(1-0.01k))。假设f[i+1}(p) = a_{i+1} * p + b_{i+1},那么代入后得到:a_ip + a_{i+1} * (p(1-0.01k)) + b_{i+1} = (a_i + a_{i+1}*(1-0.01k)) ) *p + b_{i+1}。
如果不开采,总收益是0 + f[i+1}(p) = a_{i+1} *p + b_{i+1}。
所以,比较两种情况下的系数,选择较大的那个作为当前的a_i和b_i。
因此,对于资源型星球i来说,新的a_i是max( a_i + a_{i+1}*(1-0.01k) , a_{i+1} )。而对应的b_i则是,在取较大的那个选项时对应的b项。比如,当选择开采时,b项是b_{i+1};如果不选,则b项也是b_{i+1}。所以,不管选择哪个,b项可能不变?或者说,当两种情况的a项不同时,对应的b项可能不同?
这里可能需要更仔细的分析。比如,假设f[i}(p) = max( (a_i + a_{i+1}*(1-0.01k)) ) *p + b_{i+1}, a_{i+1} *p + b_{i+1} )
所以,这里的max是两个线性函数关于p的比较。当这两个线性函数的系数不同时,比较的结果取决于p的值。但这样可能无法合并成一个单一的线性函数,因为不同情况下,最大值的表达式不同。这可能导致动态规划的递推方式变得复杂。
或者,这里是否存在某种贪心策略?比如,每个星球的操作是否应该总是选择是否进行操作,而无需考虑后续的具体情况?或者,是否某个条件可以使得操作与否的选择只与后续的某个系数有关?
或者,可能这个问题的模型可以被简化为:每个操作的选择对后续的影响是乘法的,即每个步骤的决策对p的调整是乘以某个因子。例如,资源型操作会使后续的p乘以0.01*(100 -k),而维修型则是乘以0.01*(100 +c)。这可能使得我们可以将整个问题的处理转化为累积的乘数,并将收益的计算分解为各个步骤的贡献乘以相应的乘数。
比如,假设从后往前处理,每一步的决策会影响前面的乘数。例如,如果我们选择在第i个星球进行操作,那么该操作带来的收益或损失会被后面的所有操作的乘数所放大或缩小。这样,我们可以将每个操作的影响转化为一个系数,然后通过逆序处理来累积这些系数。
假设我们有某种系数,表示从i到n的所有可能的乘数的累积,那么对于每个操作的选择,我们可以计算该操作的贡献乘以该系数。例如,在资源型星球i,如果选择开采,那么得到的a_i * p_i,而p_i等于初始p乘以之前所有选择的乘数。然后,该操作的贡献是a_i * (当前乘数的倒数?),因为后面的乘数会影响后面的操作。或者,这可能比较复杂。
或者,我们可以将整个过程看作一个链式的乘法过程。例如,每个操作之后p的变化相当于一个乘积因子。因此,如果在某个步骤i进行操作,那么该步骤的收益是该操作对应的x(a_i或b_i)乘以当前p的值,而当前p的值等于初始p乘以之前所有步骤的乘数。例如,如果前面的步骤有j1,j2,...jm的操作,则p的值为w乘以对应的各个乘数的乘积。所以,总收益可以表示为各个操作x_i * w * product(factors up to i-1) * factor_i的选择情况。但这样的话,每个操作的选择是否会影响后面的乘数,而乘数的累积会影响各个步骤的贡献。
这似乎很难直接处理,但如果我们逆序考虑的话,或许能找到递推的方式。例如,从后到前处理每个星球,维护一个系数,该系数表示后续的操作的累积乘数对当前操作的影响。
比如,假设在步骤i之后的所有操作的累积乘数是d,那么对于当前步骤i的选择,如果进行操作,那么该操作的收益是x_i * p_i,而p_i等于p_{i-1} * (某个因子)。或者,这里可能比较难以直接建模。
或者,假设我们维护一个变量,表示后续的各个乘数的累积乘积。例如,对于步骤i来说,如果当前操作的乘数是k,那么后续的乘数累积为d。那么,当前操作的总贡献是x_i * (d * k) * p_i,其中p_i是之前的乘数累积。或者,这可能不太对。
或许,正确的思路是,从后往前动态规划,维护两个参数a和b,使得从当前步骤i到末尾的总收益可以表示为a * p + b,其中p是当前步骤的钻头能力。这样,每个步骤的选择会影响这两个参数的变化。
例如,假设处理到第i个星球时,后面的总收益函数是a'和b',那么对于当前步骤的选择:
如果是资源型:
开采:收益是a_i * p + (a' * (p*(1 - 0.01k)) ) + b' → 合并为 (a_i + a'*(1-0.01k)) * p + b'
不开采:收益是0 + (a' * p ) + b' → a' * p + b'
所以,这时候应该比较这两种情况,取最大值。即,当前步骤的a和b为:
如果 (a_i + a'(1 - 0.01k)) > a' → 选择开采,此时a = a_i + a'(1-0.01k),b = b'
否则,选择不开采,此时a = a',b = b'
同样,对于维修型:
如果选择维修,则当前支出是b_i * p,所以收益是 -b_i * p + (a' * (p*(1 + 0.01c))) + b' → 合并为 (-b_i + a'*(1 + 0.01c)) ) *p + b'
不选择维修的话,收益是0 + a' p + b'
所以,比较两种情况,取较大的系数。
这样,我们就可以逆序处理每个星球,维护当前的a和b参数。初始时,最后一个星球处理完后,后面的a和b都是0,因为没有后续步骤。
这样,最终的a和b在第一个步骤之前的状态,总收益是a * w + b。因为初始的p是w。
这似乎是一个可行的动态规划方法。因为每个步骤只需要维护两个参数,所以时间复杂度是O(n),可以处理1e5的数据。
那,具体的实现步骤如下:
初始化a和b为0。因为处理完所有n个星球之后,没有后续步骤,所以收益为0。
然后,从第n个星球开始,逆序处理到第1个星球:
对于每个星球i,根据其类型,计算两种情况下的新a和b,并选择较大的那个。
比如,对于资源型:
开采的a_new = a_i + a_prev * (1 - k/100)
不开采的a_new = a_prev
比较这两个,取较大的那个。同时,对应的b_new等于b_prev。
因为对于资源型,无论是否开采,b的增量都是b_prev,所以当取较大的a时,b的值保持不变。
同理,维修型的情况:
维修的a_new = (-b_i) + a_prev * (1 + c/100 )
不开采的a_new = a_prev
同样,取较大的a_new,对应的b_new等于b_prev。
这样,整个过程只需要维护a和b两个变量,每个步骤逆序处理,最后的结果是a * w + b。
例如,样例输入中的情况:
输入:
5 50 50 10
1 10
1 20
2 10
2 20
1 30
那么,处理顺序是逆序的五个星球。初始a=0,b=0.
处理第五个星球(i=5):类型1,x=30.
资源型,比较开采和不开采的情况。
开采的a_new = 30 + 0 * (1 - 0.5) →30.
不开采的a_new =0.
所以,选择开采,a=30,b=0.
然后处理第四个星球(i=4):类型2,x=20.
维修型,比较维修和否。
维修的a_new = (-20) + a_prev*(1 + 0.5) → -20 + 30 * 1.5= -20+45=25.
不开采的a_new=30.
比较25和30,显然30更大。所以选择不维修,a=30,b=0.
第三个星球(i=3):类型2,x=10.
维修型:
维修的a_new = -10 + 30 *1.5 =-10+45=35.
不开采的a_new=30.
选择35更大,所以a=35,b=0.
第二个星球(i=2):类型1,x=20.
资源型:
开采的a_new =20 +35*(0.5) =20+17.5=37.5.
不开采的a_new=35.
选择37.5,所以a=37.5,b=0.
第一个星球(i=1):类型1,x=10.
资源型:
开采的a_new=10 +37.5*0.5= 10+18.75=28.75.
不开采的a_new=37.5.
比较的话,37.5更大。所以选择不开采?那此时a=37.5,b=0.
最终结果是aw +b=37.510 +0=375.00,与样例输出一致。
这说明这个方法是正确的。那这样,问题就转化为如何逆序处理每个星球,维护a和b的值。
那现在,我需要将这个思路转化为代码。因为n可以是1e5,所以必须用线性时间处理。每个星球处理只需要常数时间。
具体来说:
读入n、k、c、w.
然后读入n个星球的type和x,存储在一个数组中,可能需要逆序处理。
或者,读入的时候正向存储,然后逆序遍历。
例如,在Python中,可以用一个列表保存所有星球的信息,然后从最后一个元素开始到第一个元素遍历。
对于每个元素,根据type的不同,更新a和b的值。
初始a=0,b=0.
对于每个星球i(逆序处理):
如果是资源型(type=1):
开采的情况下的新a是 x + a_prev * (1 - k / 100 )
不开采的新a是 a_prev.
比较这两个,取较大的那个。这时候的a_new就是max( x + a_prev*(1 -k/100 ), a_prev )
而维修型(type=2):
维修的情况下新a是 -x + a_prev*(1 + c/100 )
不开采的新a是 a_prev.
同样取较大的那个。
而不管哪种情况,b的值都是保持为原来的b_prev。因为每个步骤的总收益函数是a*p +b,所以这里的b_prev是累积的。但根据上面的例子,b的值似乎一直保持0?这可能吗?
比如,在例子中,所有的操作都只影响a的值,而b始终为0。这说明可能在这种递推方式下,b的值始终为0。那这是为什么呢?
因为,在每一步的选择中,不管是否进行操作,总收益的计算是max( ... , ... ),而两个选项中的b项都是原来的b_prev。例如,在资源型的情况下:
开采的收益是a_ip + a_prev(p*(1 -k%)) + b_prev → p*(a_i + a_prev*(1-k%)) ) + b_prev.
不开采的收益是 a_prev *p + b_prev.
所以,不管是否选择开采,总收益的b项都是原来的b_prev。因此,在每一步的处理中,b的值不会改变,只有a的值会被更新。这似乎意味着,在整个过程中,b的值始终为初始值0。
这可能是一个关键点。因为在这种情况下,只需要维护a的值,而b始终是0。这样,代码中的b变量可能可以忽略,只需维护a即可。
那再看例子中的情况。第五个星球处理后,a是30,b是0。第四个星球处理时,比较两种情况,不管是否维修,b都是0。比如,维修的话,总收益是25p +0;不维修的话是30p+0。所以取较大的a。
这似乎意味着,对于所有步骤来说,总收益的表达式是a*p,其中a的值根据各个步骤的选择而变化。而b的值始终为0。这可能是否定的?
或者,是否有什么情况下,b的值会变化?
比如,假设在某个步骤i,某个操作不仅会改变a,还会改变b。例如,如果某个操作的收益是固定值,而不管p的值。这时候,总收益函数可能变为ap + b。但在当前的问题设定中,每个操作的收益都是与p相关的。例如,资源型开采得到a_ip,维修型支付b_ip。因此,所有的收益项都是与当前的p成正比的。所以,总收益的表达式可以表示为p乘以某个系数a,加上某个常数b吗?或者,是否所有操作后的总收益的表达式都是线性的,即可以表示为ap?
比如,在初始状态,处理完最后一个星球后,总收益是0,所以a=0。假设倒数第二个星球是资源型,开采的话,总收益是xp + a_prevp*(1 -k% )。例如,假设a_prev是0,那么总收益是xp。所以,a被更新为x。如果该步骤之后还有其他步骤,那么每个后续步骤的选择会影响a的值,但总收益始终是ap,因为所有操作的收益都是p的线性函数,没有常数项。这说明,整个递推过程中,b的值始终为0。这可能吗?
是的,因为每一步的收益都是与p的当前值相乘的,而后续的收益也都是与后续的p相乘的。因此,总收益的总和可以写成各个步骤的贡献的线性组合,而每个贡献的系数是各步骤的x乘以前面所有乘数的积。这样,整个总收益可以表示为p的系数乘以初始p的值。因此,在逆序处理的过程中,总收益的表达式仅由a*p构成,而b始终为0。这可能是一个关键点,简化了问题。
那在这种情况下,可以忽略b,只维护a的值。例如,在每一步的处理中,无论类型,总收益的表达式只是a*p。那么,对于资源型i:
选择开采的话,总收益是xp + a_prev * (p(1 -k/100 )) = [x + a_prev*(1 -k/100 )] *p.
不选择的话,总收益是a_prev*p.
因此,取这两者的最大值对应的系数作为新的a。同样,对于维修型i:
选择维修的话,总收益是 -xp + a_prev * (p(1 +c/100 )) = [ -x +a_prev*(1 +c/100 ) ] *p.
不选择的话,总收益是a_prev*p.
取最大值对应的系数作为新a。
所以,整个过程只需要维护a的值,初始为0。逆序处理每个星球,根据类型更新a的值。最终结果是a*w。
这似乎与之前的例子一致。例如,样例中的最终a是37.5,w是10,总收益是375.00。这样,b的值确实是0。
那这说明,原问题中的总收益的表达式可以简化为a*p,其中a是各个步骤的选择所决定的系数。因此,在逆序处理时,只需要维护一个变量a即可,无需处理b。
这样的话,代码可以更简单。比如,初始a=0,然后对每个逆序的星球:
如果是资源型:
a = max( x + a * (1 -k/100 ), a )
如果是维修型:
a = max( -x + a * (1 + c/100 ), a )
然后,最终答案是a * w。
这似乎就是正确的解法。那接下来,我需要将这个思路用代码实现。
那现在,如何处理k和c的百分比?例如,k=50的时候,损耗后的乘数是1-0.01*50=0.5。同样,c=50的话,乘数是1.5。
在代码中,需要注意除以100的问题。例如,可以将k转换为k_percent =k /100.0,c同理。或者,在计算的时候直接计算1 -k/100.0等。
例如,在Python中:
对于资源型:
new_a_if_choose = x + a_prev * (1 - k / 100.0)
对于维修型:
new_a_if_choose = -x + a_prev * (1 + c / 100.0 )
然后比较new_a_if_choose和a_prev的大小,取较大的作为新的a。
这样,代码的逻辑就很简单了。
现在,编写代码的步骤:
-
读取n, k, c, w。
-
读取n个星球的信息,存储为一个列表。
-
逆序遍历这个列表。
-
维护变量a,初始为0。
-
对于每个星球:
a. 如果是类型1(资源型),则x是a_i。计算选择开采后的new_a =x + a * (1 - k/100.0)。比较new_a和当前a,取较大的作为新a。
b. 如果是类型2(维修型),则x是b_i。计算选择维修后的new_a =-x + a * (1 + c/100.0)。比较new_a和当前a,取较大的作为新a。
- 最终结果a *w,保留两位小数。
这样,代码的时间复杂度是O(n),可以处理1e5的数据。
那测试样例:
输入样例中的五个星球逆序处理顺序是:
第5个星球类型1,x=30 →处理时,a被更新为30 +0*(0.5)=30.
第4个星球类型2,x=20 →比较-20 +30*1.5=35与30 →取35?或者原例子中的处理,第四个星球是维修型吗?
哦,原样例输入的顺序是:
1 10 →第1个星球,资源型,x=10.
1 20 →第2个星球,资源型,x=20.
2 10 →第3个星球,维修型,x=10.
2 20 →第4个星球,维修型,x=20.
1 30 →第5个星球,资源型,x=30.
所以,逆序处理的是第5、4、3、2、1的星球。
在处理第4个星球时,类型是2,x=20。此时a的值是30。那么维修的情况下的new_a是 -20 +30*(1+50/100) →-20+30*1.5 →-20+45=25。而当前a是30。所以比较25和30,选择30。所以,a保持30。这符合样例中的处理。
第三个星球是维修型,x=10。此时a是30。维修后的new_a是-10+30*1.5=35。所以,a更新为35.
第二个星球是资源型,x=20。此时a=35。开采后的new_a=20 +35*(0.5) →20+17.5=37.5。大于35,所以a=37.5.
第一个星球是资源型,x=10。此时a=37.5。开采后的new_a=10 +37.5*0.5= 10+18.75=28.75。比37.5小,所以不选。a保持37.5.
最终结果37.5 *10=375.00,正确。
这说明代码是正确的。
那现在,将这一逻辑编写成Python代码:
注意,在Python中,读入的输入可能有多个测试用例,但这里题目只有一个测试用例。处理逆序可以用列表的倒序遍历,比如使用:-1。
例如:
n, k, c, w = map(int, input().split())
planets = [tuple(map(int, input().split())) for _ in range(n)]
a = 0.0
for type_i, x_i in reversed(planets):
if type_i ==1:
choose = x_i + a * (1 - k /100.0 )
else:
choose = -x_i + a * (1 + c /100.0 )
a = max( choose, a )
ans = a * w
print("{0:.2f}".format(ans))
这应该可以得到正确的结果。例如,样例中的测试数据,该代码会正确输出375.00。
需要注意浮点数的精度问题。在Python中,使用浮点数计算应该不会有问题,因为题目允许保留两位小数。
那这个问题的正确解法应该是这样的。
为了解决这个问题,我们需要最大化在依次经过资源型和维修型星球后的总收益。每个星球的操作会影响后续操作的能力值,因此我们需要逆序处理这些星球,动态维护一个系数来表示当前和后续操作对总收益的影响。
方法思路
逆序处理:从最后一个星球开始逆序处理到第一个星球,这样可以更容易地处理每个操作对后续能力值的影响。
动态维护系数:维护一个系数 a,该系数表示当前和后续操作对总收益的影响。对于每个星球,根据其类型(资源型或维修型)计算选择操作后的收益,并更新系数 a。
最终计算:将最终维护的系数 a 乘以初始能力值 w,得到最大总收益。
解决代码
python
n, k, c, w = map(int, input().split())
planets = [tuple(map(int, input().split())) for _ in range(n)]
a = 0.0
for typ, x in reversed(planets):
if typ == 1:
choose = x + a * (1 - k / 100.0)
else:
choose = -x + a * (1 + c / 100.0)
a = max(choose, a)
print("{0:.2f}".format(a * w))
代码解释
输入处理:读取输入的星球数量 n、损耗百分比 k、修复百分比 c、初始能力值 w,以及每个星球的类型和参数。
逆序处理星球:从最后一个星球开始逆序遍历每个星球,动态维护系数 a。
类型判断与计算:
资源型星球:计算开采后的收益,并更新系数 a。
维修型星球:计算维修后的收益,并更新系数 a。
输出结果:将最终维护的系数 a 乘以初始能力值 w,并保留两位小数输出结果。
通过这种方法,我们能够高效地计算出最大收益,确保时间复杂度为 O(n),适用于大规模输入数据。
全部评论 2
我的妈妈呀,这……
2025-02-22 来自 浙江
1牛啊
2025-02-12 来自 福建
0
有帮助,赞一个