序
过一段时间心态好了再补,或者就搁置了。
感觉第二题很考思维,反正我是想了一整天才想通。
感觉第四题如果熟练掌握板子的话就很好想,除了离散化没有很创新的东西。
赛时总分:100+20+10+36=166(SH-0210 上海二等奖)
代码
题解
1. dict
难度评价: 普及- \colorbox{#fe9c11}{\color{#fff}\text{普及-}} 普及-
标签:模拟,排序
对每个字符串桶排序出最小和最大的可能情况,若一个字符串的最小情况小于所有其他串的最大情况即判可,然后对所有字符串按字典序排序即可。
有趣的是,我考场看错题,以为一个字符串中只能交换一次两个元素,但依然能得到正确答案。目前没想到严格证明,但是多方数据(以及直觉)验证是对的。
复杂度 O ( n m log n ) \mathcal{O}(nm\log n) O(nmlogn)。
2. tribool
难度评价: 提高+/省选- \colorbox{#3498db}{\color{#fff}\text{提高+/省选-}} 提高+/省选-
标签:模拟,搜索,思维
发现1:所有数的被赋值会导致覆盖之前值,但是不消除之前影响。发现2:由 T r u e True True 和 F a l s e False False 组成的反过来也行。
我们考虑假设 1 ∼ n 1\sim n 1∼n 的初值 a i = i a_i=i ai=i。然后模拟操作的进行,取反记负数, T r u e True True 记 1 0 5 + 1 10^5+1 105+1, F a l s e False False 记 − 1 0 5 − 1 -10^5-1 −105−1, U n k n o w n Unknown Unknown 记 0 0 0。(详见代码)然后记最终值为 v i v_i vi。
然后对每一个元素搜索赋值的根源: v i = i v_i=i vi=i 时即为根源。但是过程中会出现不合常理的情况,即 v i = − i v_i=-i vi=−i,自己等于自己的反,显然矛盾,这个值只能是 U n k n o w n Unknown Unknown,然后溯源还可能是 T r u e , F a l s e , U n k n o w n True,False,Unknown True,False,Unknown 的常量,需要特判一下。然后溯源操作类似并查集,所以直接路径压缩。
复杂度 O ( n α ( n ) ) \mathcal{O}(n\alpha(n)) O(nα(n))。
3. expand
难度评价: 省选/NOI- \colorbox{#9d3dcf}{\color{#fff}\text{省选/NOI-}} 省选/NOI-
标签:思维,dp
不妨设 x 1 < y 1 x_1<y_1 x1<y1。首先要考虑 dp。设 f ( i , j ) f(i,j) f(i,j) 表示序列 x x x 取前 i i i 个,序列 y y y 取前 j j j 个是否可行。若 x i ≥ y i x_i\ge y_i xi≥yi, f ( i , j ) = 0 f(i,j)=0 f(i,j)=0,若 x i < y j x_i<y_j xi<yj,则有 f ( i , j ) = f ( i − 1 , j ) ∣ f ( i , j − 1 ) ∣ f ( i − 1 , j − 1 ) f(i,j)=f(i-1,j)|f(i,j-1)|f(i-1,j-1) f(i,j)=f(i−1,j)∣f(i,j−1)∣f(i−1,j−1)。容易继续证明,转移方程可以再简化为 f ( i , j ) = f ( i − 1 , j ) ∣ f ( i , j − 1 ) f(i,j)=f(i-1,j)|f(i,j-1) f(i,j)=f(i−1,j)∣f(i,j−1)。复杂度 O ( q n m ) \mathcal{O}(qnm) O(qnm)。
然后我们考虑优化,若把 n × m n\times m n×m 的网格画出来,不难发现,如果我们设 x i ≥ y i x_i\ge y_i xi≥yi 的点为障碍,即找是否存在一条从 ( 1 , 1 ) (1,1) (1,1) 到 ( n , m ) (n,m) (n,m) 的只有向下或向右的路径。
我们思考 x m a x , y m i n x_{max},y_{min} xmax,ymin,假设有 x k < y m i n x_k<y_{min} xk<ymin,那么有 ∀ i , x k < y i \forall i,x_k<y_i ∀i,xk<yi。所以 x k x_k xk 这一列(或者是行,这无所谓)皆可转移到;同理考虑 x m a x x_{max} xmax,性质相似。假如不存在 k k k,可以证明不合法。然后这个网格图中有若干行和若干列是完全可以转移的,不完全可转移的是若干矩形块。
进而我们只要考虑 ( 1 , 1 ) (1,1) (1,1) 和 ( n , m ) (n,m) (n,m) 的块能否转移。以 ( 1 , 1 ) (1,1) (1,1) 块举例:考虑同时干这两件事,不断调整 x i x_i xi 到最小, y j y_j yj 最大,不断扩展可到达的最大位置,若离开当前区块则判断可以。贪心正确的理由是 x i x_i xi 到最小, y j y_j yj 最大的情况必然不劣,因为若 x a < x b x_a<x_b xa<xb,那么前者可到达的位置必然包含后者的,所以若这样贪心找不到,那么其他情况也找不到。注意,由于我们这里极力让 x , y x,y x,y 可到达的位置最大,所以处理 ( n , m ) (n,m) (n,m) 时要反过来推才正确。复杂度 O ( q ( n + m ) ) \mathcal{O}(q(n+m)) O(q(n+m))。
4. run
难度评价: 提高+/省选- \colorbox{#3498db}{\color{#fff}\text{提高+/省选-}} 提高+/省选-
标签:dp,离散化,线段树
对于 f i f_i fi 表示时间 i i i 不打卡的最大能量值,则有转移: f i = max j = i − k − 1 i − 1 { f j + w ( j + 1 , i − 1 ) − d ( i − 1 − j ) } f_i=\max_{j=i-k-1}^{i-1}\left\{f_j+w(j+1,i-1)-d(i-1-j)\right\} fi=j=i−k−1maxi−1{fj+w(j+1,i−1)−d(i−1−j)} 其中 w ( l , r ) w(l,r) w(l,r) 表示从 l l l 到 r r r 天都打卡的获取的能量,但是我们不需要直接求出 w ( l , r ) w(l,r) w(l,r),由于其便于扩展,只要在过程中不断维护就可以了。具体来讲,对于一个挑战 ( x i , y i , v i ) (x_i,y_i,v_i) (xi,yi,vi),当遍历到 i = x i i=x_i i=xi 时,我们把 1 ≤ j ≤ x i − y i 1\le j\le x_i-y_i 1≤j≤xi−yi (左端点到 1 1 1 是正确的,连续小于 k k k 天的限制我们在转移中维护)区间加 v i v_i vi,这样我们可以实时维护 f j + w ( j + 1 , i − 1 ) f_j+w(j+1,i-1) fj+w(j+1,i−1)。发现还有一坨 − d ( i − 1 − j ) -d(i-1-j) −d(i−1−j),可以参变分离,将维护内容改为 f j + w ( j + 1 , i − 1 ) + d ⋅ j f_j+w(j+1,i-1)+d\cdot j fj+w(j+1,i−1)+d⋅j,区间查询后再 − d ( i − 1 ) -d(i-1) −d(i−1)。
复杂度 O ( t n log n ) \mathcal{O}(tn\log n) O(tnlogn)。
然后离散化,这题的离散化我觉得挺难的,需要仔细考虑。因为一个挑战从 x i − y i + 1 x_i-y_i+1 xi−yi+1 开始,而到 x i x_i xi 就无关了,如果不考虑其他挑战则必然不用将开始时间提前,或将结束时间延后。对于所有挑战这样考虑,发现一个挑战的关键点是 x i − y i x_i-y_i xi−yi 与 x i + 1 x_i+1 xi+1(因为转移是不跑步的时间,这样设关键点便于转移)。那么可以离散出 2 m 2m 2m 个关键点,可行。但是我们的转移方程是在时间上的,所以所有时间都要映射回离散的序号。预处理不好,因为转移中的时间不一定一一对应离散的值,需要取大于(或小于)它的第一个离散值。同时以上原因导致 f i = f i − 1 f_i=f_{i-1} fi=fi−1 不能保证推出,需要手动维护上一个 f i f_i fi 不跑步的情况。
复杂度 O ( t m log m ) \mathcal{O}(tm\log m) O(tmlogm)。
记得开 long long
我有个地方忘了转类型,导致调了半天,所以实在嫌麻烦还是 define int long long
吧。