当事与愿违的时候,选择自己心中所想

本文回顾了一位程序员从不了解Java到独立完成项目、解决各种问题的四年历程,分享了探索未知、解决问题的喜悦,以及在公司工作多年后的自我反思。文章表达了对技术追求的坚持,以及跳出舒适圈的决心,立志将代码写成诗,用双手改变世界。

        之所以现在开始写博文,第一是想跟同行业的朋友有一个交流的平台,再者就是整理下之前的知识点,记录下以后遇到的一些问题。
        从开始不知道Java是什么到现在能独立的完成项目,解决各种Bug,实现各种功能,已经过去四年之久了,这些年来有对未知探索的兴奋,有亲手解决问题的激动,到自己亲自参与一个项目直到完成的开心,有满足有感动。
        但有时候也有困惑,在一个公司工作这么久始终有种不舍,之前是哪里需要什么就学习什么,哪里用到什么就去研究什么,直到当越来越多的项目去维护,尤其是越来越多的人需要沟通的时候,发现距离自己真正的心中所想越来越远了。

        真的有点远了,觉得自己应该有自己的路要走。后来自己开始了学习的新的征程,从基础,线程,并发,网络,nio,反射... 一路学习下来收获很多,直到最近读了编程范式,设计模式,OOP思想,我发现一直被困在一个小圈子里,做着类似“培训”工作的时候真的累了,这不是我想要的。
        这种时候不自觉的想跳出这个圈子,静下心来好好想想自己的以后,下一步怎么做。在一个公司很久之后会有很多种感情,有感激,有迷惑,有自己以后路的一些迷茫,始终觉得自己是那种追求技术,追求完美的人,愿意学习。但工作是不会照顾自己的感受来进行的,所以这篇博文作为自己的一个反省吧,也作为自己的一个开始,同时也是自己给自己的一个鼓励,相信自己的选择,走下去,去实现自己的最初的梦想--把代码写成诗,用双手来改变世界。

<think> 题目要求:在a+b+c天中,有a天加训(疲劳度+1)、b天休息(疲劳度不变)、c天颓废(疲劳度-1)。初始疲劳度为0。我们需要安排这些天的顺序,使得在整个过程中,疲劳度恰好为0的天数尽可能多。注意,疲劳度为0的天数包括初始状态(第0天)吗?题目没有明确,但通常我们只考虑过程(即第1天到第a+b+c天)。然而,注意初始状态(第0天)疲劳度为0,但题目要求的是在接下来的天中,所以应该包括第0天吗?题目没有说明,但一般安排的是从第一天开始的活动,所以通常我们只考虑活动安排过程中(即从第1天到第a+b+c天)的每一天。但是,初始状态(第0天)是否计入?题目没有明确要求,我们重新审视问题。 问题描述:“在接下来的a + b + c天中”,所以活动安排是从第1天到第a+b+c天。初始状态(第0天)可能不算在“接下来”的每一天中。而且,疲劳度变化发生在每天之后,所以第0天(初始状态)是开始,然后第一天结束后有一个疲劳度值,第二天结束后有一个疲劳度值,等等。因此,我们考虑的是在这a+b+c天结束后,每天结束后的疲劳度值是否为0,以及在这a+b+c天的过程中,每一天结束后的疲劳度值为0的次数。 但是,注意:初始状态(第0天)时疲劳度为0,但这一天并不是“接下来的a+b+c”天中的一天。所以,我们只考虑第1天到第a+b+c天结束时的疲劳度值。然而,问题要求“疲劳度为0的天数最多”,这个天数是指哪一天?是指每一天结束后的疲劳度值。 另外,题目要求输出的是最多有多少天疲劳度为0。 因此,我们需要最大化在a+b+c天中,每天结束后的疲劳度值为0的次数。 我们用一个变量s表示当前的疲劳度。初始时s=0(第0天结束的状态,但第0天不算在接下来的天数中)。然后,在接下来的每一天,我们选择做一种活动:加训(s=s+1)、休息(s不变)、颓废(s=s-1)。我们要统计在整个过程中(即第1天到第a+b+c天)每天结束后的s值等于0的次数。 注意:第0天结束的s=0并不计入,因为我们只考虑接下来的a+b+c天。 问题:如何安排这a+b+c天的活动顺序,使得每天结束后的疲劳度值为0的次数最多? 这是一个经典问题,我们可以通过动态规划或者贪心策略来解决。但是,由于a,b,c可能很大(题目没有给出范围,但一般会比较大),我们需要一个数学解法。 观察:我们关心的是s=0的次数。而s的变化可以看作是一条折线,从0开始,每一步可以+1,0,-1。我们希望经过0的次数尽可能多。 一个重要的性质:折线在0的次数与折线在0上下震荡的次数有关。另外,我们也可以考虑使用贪心策略:尽可能让折线在0附近波动。 但是,我们注意到有三种操作:+1,0,-1。其中0操作不会改变疲劳度,所以我们可以把0操作当作是“断开”的,即把整个序列分成若干段,每一段由+1和-1操作组成。而0操作可以在任意位置插入,不影响疲劳度值的变化。 因此,我们可以先忽略休息日(b天),只考虑加训和颓废(a天和c天)。那么,问题转化为:在a天+1和c天-1的序列中,插入b天休息(这些休息日可以任意插入,且不改变疲劳度),如何安排序列使得整个过程中疲劳度等于0的次数最多? 注意:休息日虽然不改变疲劳度,但是休息日当天结束时的疲劳度值可能是0,所以休息日也可能贡献一个0。同样,加训和颓废日结束时的疲劳度值也可能是0。 因此,我们需要同时考虑三种操作。 一种思路是:我们可以枚举在序列中每个位置,并计算到该位置时的疲劳度值。但这样枚举排列显然不可行。 另一种思路:我们考虑整个过程中,疲劳度值等于0的次数与序列的排列顺序的关系。实际上,我们关心的是折线从负到正或者从正到负经过0的次数,以及停留在0的次数。 注意:折线每次穿过0(从正变成负或从负变成正)都会经过0,并且折线停留在0(即连续多天为0)也是可以的。但是,由于我们每一步变化只能是±1或0,所以停留在0的情况只能是通过0操作(休息)或者连续的+1和-1操作交替。 实际上,如果我们把休息日都安排在疲劳度为0的时候,那么每个休息日都会增加一个0。因此,我们首先需要知道在去掉休息日后,我们最多能有多少个0(包括起?但起不算,因为起是第0天结束,不算在接下来的天数中),然后再加上在0处插入休息日带来的额外0。 但是,起(第0天结束)的疲劳度为0,但不算在接下来的天数中,所以不考虑。那么,我们考虑从第1天开始的活动序列。 重新定义:从第1天开始,每天操作后都会有一个疲劳度值。我们设第i天结束后的疲劳度为s_i。其中s_0=0(第0天结束时,即开始)但我们不统计s_0,我们只统计s_1, s_2, ..., s_{a+b+c}。 我们的目标就是最大化满足s_i=0的i的个数(i从1到a+b+c)。 如何高效计算? 思路:使用动态规划。状态:dp[i][j]表示前i天结束后疲劳度为j,且这前i天中疲劳度为0的最大天数。其中i的范围是0到a+b+c,j的范围可能是负数,所以我们需要一个偏移量。 但是,a,b,c的范围未知,如果很大,那么疲劳度j的范围可能很大(最大不超过a+b+c,最小不低于-(a+b+c)),所以状态空间可能是O(N^2)(N=a+b+c),而N最大可能几千或几万?题目没有说,如果N=1000,那么状态数就是1000*2000=2e6,这是可以接受的。但题目要求不用vector和指针,我们可以用二维数组,但要求简化变量名。 然而,题目要求不用vector和指针,我们可以用二维数组,但是数组的第二维大小需要动态确定(因为疲劳度有正负),我们可以用静态数组,但需要确定最大范围。假设a,b,c最大为2000,那么总天数最大6000,疲劳度范围-6000到6000,需要12001个状态。那么状态数就是6000*12001,大约7.2e7个状态,空间和时间可能超限(C++大约需要7.2e7个整数,每个整数4字节,大约288MB,可能超出空间限制,时间上每个状态转移O(1)也是7.2e7,在1秒内可能勉强通过,但题目要求更高效)。 我们需要更高效的方法。 数学方法: 设序列中+1有a个,-1有c个,0有b个。我们考虑整个序列的疲劳度变化。我们用三个变量x,y,z分别表示已经使用的加训、休息、颓废的天数。那么当前的疲劳度s = (x) - (z) = x - z。 我们希望统计有多少天结束后的疲劳度为0,即有多少个位置满足x_i - z_i = 0。 另外,在序列中,每个休息日(0)的位置,疲劳度等于前一个位置(因为休息日不改变疲劳度)。所以,如果我们已经知道了一个非休息序列(只有+1和-1)的疲劳度变化,那么插入休息日就可以在任意位置插入,只要休息日当天的疲劳度值等于0,那么这一天就贡献一个0。 因此,我们可以先考虑没有休息日(b=0)的情况:只有a个+1和c个-1。那么序列是一条折线,从0开始,每一步+1或-1。我们要求折线经过0的次数(不包括起)。折线经过0的次数等于折线从0下方穿越到上方或上方穿越到下方的次数?实际上,折线每次从正变负或从负变正都会穿过0,但是折线也可能恰好停留在0(即某一步之后到达0)。注意:每一步之后都有一个状态。 在只有+1和-1的情况下,折线在第k步后的状态s_k = (+1的个数) - (-1的个数)。那么,在序列中,如果某个前缀中+1的个数等于-1的个数,那么该前缀的末尾就会达到0。 因此,在只有+1和-1的序列中,0的次数等于前缀和等于0的次数(这里前缀和定义为+1和-1的差值之和,也就是当前疲劳度)。 注意:前缀和等于0,这个0出现的次数最多是多少?我们需要安排序列使得前缀和等于0的次数尽可能多。 在序列中,我们要求前缀和等于0的次数。那么,最大值是多少? 考虑一个序列,我们尽可能多地让前缀和等于0。例如,我们可以构造:先放一个+1,再放一个-1,这样前缀和序列为:1,0。然后再放一个+1,再放一个-1,又会得到0。这样,我们可以构造min(a,c)次“交替对”,每对(一个+1和一个-1)可以产生两个状态:第一个状态(+1后)为1,第二个状态(-1后)为0。因此,每对产生一次0(在第二个状态)。但是,第一个状态不是0。 另外,整个序列的最后状态也是a-c。如果a>c,那么最后的状态是正数,否则是负数。 那么,在只有+1和-1的情况下,0的最大次数是多少?实际上,我们可以构造序列,使得0出现min(a,c)次(因为每对产生一个0,并且一共min(a,c)对)。但是,是否可能更多?比如,我们能否让0出现min(a,c)+1次? 考虑:如果我们希望出现k次0,那么序列必须被划分为k段,每一段的前缀和都为0(即每一段内+1和-1个数相等)。但是,整个序列的前缀和是从0开始,到a-c结束。所以,如果我们希望有k个前缀和等于0,那么这些0将序列分成k段,每段内+1和-1个数相等(设第i段有x_i个+1和x_i个-1),那么总+1个数为x_1+x_2+...+x_k,总-1个数为x_1+x_2+...+x_k,所以必须有a=c,且k<=a(因为每段至少需要1对,所以k最大为a)。如果a≠c,那么整个序列结束时不为0,所以我们不可能在最后一段也达到0(最后一段结束必须是a-c≠0)。因此,如果a和c不相等,最多只能有min(a,c)段(即min(a,c)个0)。 但实际上,我们考虑前缀和等于0的,除了分段,还可以考虑起(但起不算在内)。所以,在序列中间,我们最多可以实现min(a,c)次0。例如:a=2,c=1,那么我们可以构造:+1,-1,+1。这样,前缀和:1,0,1。只有一次0(在第二个位置)。而如果我们构造:-1,+1,+1,前缀和:-1,0,1,也只有一次0。如果我们构造:+1,+1,-1,前缀和:1,2,1,没有0。所以最大为1,等于min(a,c)=1。 再例如:a=c=2,那么我们可以构造:+1,-1,+1,-1:前缀和:1,0,1,0。这样有两次0。也可以构造:+1,+1,-1,-1:前缀和:1,2,1,0,只有一次0。所以最大为2次。 因此,在只有+1和-1的情况下,0的最大次数为min(a,c)。 但是,我们还没有考虑休息日。休息日可以插入在序列的任何位置。如果我们在一个疲劳度为0的位置插入休息日,那么这一天结束后的疲劳度也是0,所以会额外增加一个0。但是,如果我们插入的位置不是0,那么休息日当天的疲劳度不是0,所以不增加0。 因此,我们的策略是:尽可能在0处插入休息日。这样,每个休息日都会增加一个0。而在非0插入休息日,不会增加0。 那么,休息日可以全部插入到0位置吗?注意,0位置可能不止一个,而且同一个0位置可以插入多个休息日吗?可以,比如在某个0位置,我们可以连续插入多个休息日,这样每一天结束后的疲劳度都是0,所以每个休息日都贡献一个0。 因此,我们可以在每个0位置插入任意多个休息日。那么,如果我们能够构造出k个0(在非休息日序列中,即只有+1和-1的序列中),那么我们就可以在每一个0位置插入任意多个休息日,包括0个。那么,我们最多可以利用休息日增加b个0(因为休息日只有b个,并且每个休息日插入到0位置都能增加一个0)。 但是,注意:在同一个0位置插入多个休息日,那么这些休息日都会产生0,所以b个休息日都可以安排在0位置(只要我们有至少一个0位置,就可以安排任意多个休息日,因为它们可以连续安排)。那么,如果我们能够构造出至少一个0位置,我们就可以把所有的休息日都安排在这个0位置,从而增加b个0。 然而,我们还要考虑非休息日序列中的0:有k个0(k>=1),那么非休息日序列中已经有k个0了。然后我们把b个休息日全部安排在某个0位置(或者分散到各个0位置),那么总共的0个数就是k(非休息日中的0)+ b(休息日中插入到0位置带来的0)。 但是,这里有一个问题:休息日插入的位置,这个位置本身也是序列中的一个位置,而且这个位置可能是非休息日序列的0位置,那么在这个位置插入休息日,实际上休息日当天结束后的疲劳度也是0,所以这个位置原本就已经是一个0(由非休息日序列产生的),现在又增加了一个休息日的0?不对,这里需要澄清:非休息日序列的0是由非休息日产生的,比如一个-1之后,疲劳度变为0,这一天是非休息日(-1)。如果我们在这一天后面插入休息日,那么休息日是在之后的日子。但是,如果我们在非休息日序列的两个非休息日之间插入休息日,那么插入的休息日当天结束的疲劳度等于前一个非休息日结束时的疲劳度。 因此,如果我们把休息日插入到某个非休息日序列的0位置(即前一个非休息日结束后疲劳度是0),那么休息日当天结束的疲劳度也是0(因为不变)。所以,这个休息日贡献一个0。 同时,非休息日序列的0(即那个非休息日)本身已经贡献了一个0。所以,同一个0值(位置)上,我们可以有多个0:一个由非休息日产生(比如一个-1使得到达0),然后在它后面连续插入休息日,那么休息日每一天都是0。所以,同一个0值位置(在折线上是一个)可以对应多个天数(多个0)。 因此,总0个数 = 非休息日序列中的0个数 + b(因为b个休息日都可以安排在0位置,从而每个休息日都贡献一个0)。 但是,前提是非休息日序列中至少有一个0。如果非休息日序列中没有0,那么休息日只能安排在非0位置,这样休息日就不会贡献0(除非休息日当天恰好疲劳度为0,但当前安排在没有0,所以疲劳度非0?不对,如果我们把休息日安排在非0位置,那么休息日当天的疲劳度等于前一天的疲劳度(非0),所以不是0。因此,如果非休息日序列中没有0,那么休息日不会带来任何0。 那么,非休息日序列中没有0的情况是什么?即a个+1和c个-1,但是没有任何一个前缀和为0。例如,a=0,c>0,那么序列全是-1,疲劳度从0开始,然后-1,-2,...,没有0。同样,c=0,a>0,也没有0。另外,如果a>c,并且序列一开始就是连续的+1,那么前缀和一直为正,没有0?不一定,我们可以在中间插入-1,但是即使这样,如果我们构造不当,可能没有0。但注意,前面我们说过,非休息日序列的0个数可以达到min(a,c)。那么,如果min(a,c)=0(即a=0或c=0),那么非休息日序列中没有0。 结论: 1. 如果min(a,c)=0,那么非休息日序列中没有0(因为要么只有+1,要么只有-1,或者没有非休息日)。那么,休息日也无法贡献0(因为只能安排在非0)。那么,整个过程只有0个0?但是,注意:如果一开始就是0(第0天结束)不算,那么第一天结束后的疲劳度可能是非0。但是,有没有可能自然出现0?比如,如果a=0,c=0,那么全是休息日,那么每一天结束后的疲劳度都是0!所以我们需要分情况讨论。 2. 如果a=0且c=0,那么全部是休息日,那么每天结束后的疲劳度都是0,所以有a+b+c = b = b天都是0。所以0天数为b。 3. 如果min(a,c)=0,但a>0或c>0,那么非休息日序列中没有0(因为只有一种非休息操作,或者没有非休息操作(但这种情况a=c=0已经排除))。此时,休息日安排在非0位置,所以休息日不是0。那么,非休息日序列中也没有0(因为只有一种非休息操作,不会出现0)。所以整个过程中,只有休息日安排的位置不会改变疲劳度,所以疲劳度要么一直是正数(如果a>0)要么一直是负数(如果c>0),或者如果a=c=0则全是0(已经考虑)。所以,0天数为0?但是,这里有一个例外:如果初始状态是0,那么第一天我们安排一个休息日,那么第一天结束后的疲劳度还是0,这就是一个0。注意:我们只考虑第1天到第a+b+c天结束后的状态。所以,即使非休息日序列没有0,休息日安排在任意位置,那么休息日当天的疲劳度等于前一天结束的疲劳度。而第一天如果是休息日,那么第一天结束后的疲劳度等于第0天结束的疲劳度(即0),所以第一天结束后的疲劳度是0。因此,如果第一天安排休息日,那么第一天就会有一个0。 同样,如果我们在某一天安排休息日,而前一天结束后的疲劳度恰好为0,那么这一天结束后的疲劳度也是0。但是,在非休息日序列没有0的情况下,整个序列的前一天结束的疲劳度什么时候为0?只有可能是在第0天结束(疲劳度为0)。所以,只有安排在第1天的休息日,才会使得第一天结束的疲劳度为0。如果我们安排休息日在其他天,那么它前一天的疲劳度(由非休息日序列累积)一定非0(因为非休息日序列没有0,而且休息日不会改变疲劳度,所以一旦我们安排了一个非休息日,那么之后所有天如果没有出现0,那么疲劳度就不会再回到0)。因此,在非休息日序列没有0的情况下,我们最多只能有一个0:即安排在第1天的休息日。 那么,我们是否可以在第1天安排休息日?可以。那么第一天结束后疲劳度为0,这是一个0。之后,如果我们安排非休息日(+1或-1),那么疲劳度变成1或-1,然后后面的休息日安排在这些非0,就不会产生0。所以,整个序列最多只能有一天是0(即第一天安排休息日)。 但是,如果我们在第一天安排非休息日,那么第一天结束后疲劳度就不是0,然后后面安排休息日也不会变成0,所以整个序列就没有0。 因此,在min(a,c)=0(且a>0或c>0)的情况下,如果b>=1,那么我们可以通过在第1天安排休息日,获得1个0;如果b=0,那么一个0都没有。 另外,还有一种情况:如果min(a,c)>0,那么非休息日序列中最多可以有min(a,c)个0。然后,我们可以把b个休息日全部安排在0位置(包括非休息日序列的0位置),从而得到min(a,c)+b个0。 但是,是否可能比min(a,c)+b还多?不可能,因为非休息日序列最多min(a,c)个0,而休息日最多贡献b个0(并且要求安排在0位置才能实现,而0位置由非休息日序列提供)。 那么,我们还需要考虑初始状态:第0天结束疲劳度为0,但不算在序列中。所以,我们只统计第1天到第a+b+c天。 综上所述,总0天数: 1. 如果a=c=0,则全部是休息日,0天数为b。 2. 如果min(a,c)=0且a+b+c>0(即a>0或c>0),那么: - 如果b>=1,那么我们可以得到1个0(通过把至少一个休息日放在第一天)。 - 如果b=0,那么0天数为0。 3. 如果min(a,c)>0,那么0天数为min(a,c) + b。 但是,这里有一个问题:在情况2中,我们只能得到1个0?但是,如果我们有多个休息日,并且我们只把其中一个放在第一天,那么第一天有一个0。那么,其他休息日呢?如果我们把其他休息日放在第一天之后,那么这些休息日当天的疲劳度等于前一天结束的疲劳度。由于第一天是休息日,第一天结束后疲劳度为0,第二天如果我们安排非休息日(+1或-1),第二天结束后的疲劳度就是1或-1,那么第三天如果安排休息日,那么第三天结束后的疲劳度还是1或-1,不是0。所以,其他休息日不会产生0。因此,在情况2中,无论b有多大,最多只能有一个0(即第一天安排休息日)。 那么,我们是否有可能得到更多的0?比如,在非休息日序列中,如果我们能够构造出0,那么就可以安排多个休息日。但是,在min(a,c)=0的情况下,非休息日序列中无法构造0。所以,情况2中最多1个0。 另外,在情况3中,我们得到min(a,c)+b个0。但是,有没有可能更多?比如,在非休息日序列中,我们可能通过特别的排列,使得0的个数超过min(a,c)?前面我们已经分析过,非休息日序列的0个数最多为min(a,c)。所以,情况3的最大值就是min(a,c)+b。 但是,我们还要考虑一种特殊情况:在非休息日序列中,我们可能获得超过min(a,c)的0吗? 考虑a=3,c=3,我们构造:+1,-1,+1,-1,+1,-1,那么0出现在第2,4,6天,共3次(min(a,c)=3)。还可以构造:+1,+1,-1,-1,+1,-1,那么前缀和:1,2,1,0,1,0。只有2次0。所以无法超过3。 因此,结论: 总0天数 = 如果a==0 && c==0: b 否则如果a==0 || c==0: min(b,1) # 因为如果b>=1,则最多1个0;如果b=0,则0个。 否则: min(a,c) + b 但是,我们再看一个例子:a=1,c=1,b=0。那么按照上述,min(a,c)=1,所以总0天数为1。实际:我们可以安排+1,-1:第一天结束:1,第二天结束:0 -> 1个0。或者安排-1,+1:同样1个0。正确。 另一个例子:a=1,c=1,b=1。那么总0天数=1+1=2。我们可以这样安排:第一天+1(疲劳度1),第二天休息(安排在0?不行,因为第二天开始疲劳度1,休息后还是1,不是0)。但是,我们可以在第一天休息,然后第二天+1,第三天-1:第一天结束后0(休息),第二天结束后1,第三天结束后0。所以两个0:第一天和第三天。或者:第一天+1,第二天休息,第三天-1:第一天1,第二天1(休息),第三天0。那么0只有第三天?第一天休息日:那么第一天结束是0(因为初始0),所以第一天有一个0;第三天结束是0,所以两个0。所以确实2个。 再考虑情况2:a=1,c=0,b=1。那么min(a,c)=0,所以总0天数=min(b,1)=1。实际:我们可以安排休息日在第一天:第一天休息(0),第二天+1(1)。那么第一天结束是0,第二天结束是1。所以0只有第一天。或者安排在第二天:第一天+1(1),第二天休息(1)。那么0天数0?但是,如果我们第一天安排休息日,则有一个0。所以最大值是1。正确。 再考虑a=1,c=0,b=0:总0天数为0。 但是,还有一种情况:a=0,c=0,b=1,那么总0天数为b=1。 所以,我们可以写出代码: ```cpp #include <iostream> #include <algorithm> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; int ans; if (a == 0 && c == 0) { ans = b; } else if (a == 0 || c == 0) { ans = (b > 0) ? 1 : 0; } else { ans = min(a, c) + b; } cout << ans << endl; return 0; } ``` 但是,我们再看一个边界:a=0,c=0,b=0,那么输入为0,输出0。正确。 但是,上述情况2中,如果a>0且c>0,那么我们用min(a,c)+b。但是,如果a和c都不为0,但min(a,c)=0?不可能,因为min(a,c)至少为1(因为a>0且c>0,所以最小值至少为1)。 所以,我们可以简化: ```cpp #include <iostream> #include <algorithm> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; int ans; if (a == 0 && c == 0) ans = b; else if (a == 0 || c == 0) ans = (b > 0) ? 1 : 0; else ans = min(a, c) + b; cout << ans << endl; return 0; } ``` 但是,还有一种情况:如果a和c都不为0,但b=0,那么ans=min(a,c)。正确。 再考虑一种:a=0,c=0,b=5,输出5。正确。 另一种:a=0,c=1,b=3,输出1(因为min(a,c)=0,所以进入情况2,b>0所以输出1)。 但是,这里有一个问题:在情况2中,如果a=0且c>0,或者a>0且c=0,那么非休息日序列没有0,但是我们通过第一天安排休息日,可以得到一个0。那么,如果b>1,除了第一天安排休息日,我们能否在后面的序列中再得到0? 例如:a=0,c=2,b=2。那么,序列:我们第一天安排休息日(得到0),然后后面两天安排两个-1:第二天结束:0-1=-1,第三天结束:-1-1=-2。这样,我们第一天得到一个0。然后,我们在第四天再安排休息日,那么第四天结束的疲劳度=-2,不是0。所以,如果我们把另一个休息日安排在第二天:第一天休息(0),第二天休息(0)(因为第一天结束是0,第二天休息还是0),然后第三天和第四天安排两个-1:这样,第一天和第二天都是0。那么,0天数等于2。 因此,在情况2中,我们是否能够获得多个0?关键看第一个非休息日之前可以连续安排多少个休息日。因为在第一个非休息日之前,所有的休息日都会继承初始的0(因为第0天结束是0),所以这些休息日每天的疲劳度都是0。因此,在第一个非休息日之前连续安排k个休息日,就会得到k个0(每一天结束都是0)。 然后,在第一个非休息日之后,如果安排休息日,那么这些休息日当天的疲劳度等于前一个非休息日结束的疲劳度。由于非休息日序列都是同一种操作(比如全是-1),那么第一个非休息日结束后,疲劳度变为-1(如果c>0,a=0),然后第二个非休息日结束后变为-2,依此类推。所以,在第一个非休息日之后,休息日只能安排在疲劳度为负数的位置(不可能为0),所以不会产生0。 因此,在情况2中,我们最多可以在第一个非休息日之前连续安排休息日,从而得到连续的0。连续安排的天数最多为b(因为一共b个休息日)。那么,0天数就等于在第一个非休息日之前连续安排休息日的天数。 那么,我们最多可以安排多少天?最多b天(全部安排在开头),那么0天数就是b天(因为每一天结束都是0)。 但是,这样做的前提是我们把所有的休息日都安排在开头,然后后面安排非休息日。那么,整个序列的前b天都是休息日,第b+1天开始是非休息日(比如-1)。这样,前b天每天结束的疲劳度都是0(因为从0开始,然后休息日不变)。所以,0天数就是b。 然后,后面非休息日部分(a天或者c天)没有0(因为都是同一种操作,且不为0)。所以,总0天数为b。 那么,之前我们为什么认为只能得到1个0?因为我们只考虑了一天休息日。实际上,我们可以连续安排多天休息日,全部在开头,从而得到b个0。 所以,情况2应该修改:我们可以得到b个0(通过把所有的休息日安排在开头),不管b有多大。 那么,是否意味着情况2中,0天数就是b? 再看:a=0,c=1,b=1:安排休息日在第一天:第一天结束0,然后第二天-1(结束-1)。所以0天数1(等于b)。如果b=2:第一天休息(0),第二天休息(0),第三天-1(-1)。所以0天数2(等于b)。 因此,情况2中,我们可以得到b个0(只要把休息日全部放在开头)。 那么,情况1呢?a=0,c=0,b>0:全部是休息日,0天数b。这其实也可以看作是情况2的特例(a=0,c=0),但是我们的情况2条件(a==0 || c==0)包括了这个特例。所以,我们可以统一情况1和情况2:如果a==0 || c==0,那么0天数为b。 但是,注意:如果a==0且c==0,那么b个休息日,所以0天数为b。如果a==0且c>0,那么0天数也是b?因为我们把休息日全部安排在开头,得到b个0。然后后面c个-1,不会产生0。所以整个序列0天数就是b。 同样,如果a>0且c==0,也是把休息日安排在开头,得到b个0,后面a个+1也不会产生0。所以0天数也是b。 那么,情况3:min(a,c)>0(即a>0且c>0),那么0天数为min(a,c)+b。 所以,总0天数: 如果a>0且c>0:min(a,c)+b 否则:b 注意:否则的情况包括:a=0或者c=0(或者同时为0)。 因此,我们可以这样写: ```cpp #include <iostream> #include <algorithm> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; int ans = b; if (a > 0 && c > 0) { ans += min(a, c); } cout << ans << endl; return 0; } ``` 这样,如果a>0且c>0,那么加上min(a,c);否则,就是b。 验证: 1. a=1,c=1,b=1 -> 1+1=2(正确) 2. a=0,c=1,b=1 -> 1(正确) 3. a=0,c=0,b=1 -> 1(正确) 4. a=1,c=0,b=1 -> 1(正确) 5. a=0,c=0,b=0 -> 0(正确) 6. a=3,c=2,b=4 -> min(3,2)=2+4=6(正确) 但是,我们再看情况3:a>0,c>0,但b=0,那么就是min(a,c),正确。 那么,为什么情况2中,0天数等于b?因为我们可以把所有的休息日安排在开头,从而得到b个0。然后后面的非休息日序列(只有一种操作)不会产生任何0。而在情况3中,我们除了休息日带来的b个0,非休息日序列本身还能产生min(a,c)个0。 所以,这个解法覆盖了所有情况。 因此,最终代码: </think> 以下是满足要求的C++代码,用于计算在给定条件下疲劳度为0的最大天数: ```cpp #include <iostream> #include <algorithm> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; int r = b; if (a > 0 && c > 0) r += min(a, c); cout << r << endl; return 0; } ``` ### 算法说明 1. **输入处理**:读取三个整数 $a$(加训天数)、$b$(休息天数)、$c$(颓废天数)。 2. **基础计算**:将休息天数 $b$ 作为基础值存入 $r$(因为休息日可安排在开头产生 $b$ 个疲劳度为0的天数)。 3. **条件判断**:若同时存在加训和颓废天数 $(a>0 \land c>0)$,则增加 $\min(a,c)$ 个疲劳度为0的天数(通过交替安排加训和颓废实现)。 4. **输出结果**:最终 $r$ 值即为最大疲劳度为0的天数。 时间复杂度:$O(1)$(仅含常数时间操作) 空间复杂度:$O(1)$(仅使用固定数量的变量) ### 示例说明 - 输入 `a=2, b=3, c=1`:输出 `4`($ \min(2,1) + 3 = 4$) - 输入 `a=0, b=5, c=0`:输出 `5`(仅休息日产生5个0) - 输入 `a=3, b=0, c=2`:输出 `2`($ \min(3,2) + 0 = 2$) ### 相关问题 1. 如果要求输出具体安排方案,算法应如何修改? 2. 当疲劳度变化规则改为 $\pm2$ 时,算法需要如何调整? 3. 如何验证该算法对边界情况(如 $a+b+c=0$)的处理正确性?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值