CF1882E2 Two Permutations (Hard Version)
好题啊,E1 的构造已经让我想了好久了,E2 的第一步转化真的很妙!
需要最优化,首先考虑 dp,但是发现 dp 状态难以定义,所以需要对操作进行一些转化。
考虑在排列的开头加一个 0 0 0 ,标记整个排列的开头位置。当对位置 x x x 进行一次操作时,等价于将位置 x x x 与 0 0 0 的位置进行交换。
操作完后,整个序列就是从 0 0 0 开始往后的数循环构成的排列,这样我们就完成了 O ( 1 ) O(1) O ( 1 ) 的交换操作,而且交换两个元素也比原题意的神笔操作正常一些。
由于 n , m ≤ 2500 n,m\le 2500 n , m ≤ 2 5 0 0 ,所以考虑枚举两个排列最后的形态(即 0 0 0 的位置),随后对于每一种最终状态。
对于一种对应的状态,对应点之间连边后,最少步数是去除所有一元环后,所有 0 0 0 不在的环的步数是环长 + 1 +1 + 1 ,0 0 0 所在的环的步数是环长 − 1 -1 − 1 。而如果要多一些步数去拟合另一个排列,可以操作 2 2 2 次。
将所有结束状态分为奇偶两类,对应的取 min \min min 即可,构造方案是容易的。
感觉最为逆天的地方还是在于第一步加入一个 0 0 0 的转化,后面的做法还是较为套路的。
CF1879F Last Man Standing
这个题的意义在于让你突破思维定势,如果你被套路所局限,那么你终究只能度过一个相对失败的人生,,。
比较套路的想法是你对于每个 a a a 进行上取整的整出分块,然后直接去扫描这 n A n\sqrt A n A 个分界点,时时维护最大值与次大值,但这种做法实现最优秀时复杂度也只能做到 O ( n A ) O(n\sqrt A) O ( n A ) ,根本无法通过该题。
接下来尝试打破思维定势(其实这也是另一种套路吧),先去枚举 x x x ,随后枚举 ⌈ a x ⌉ \lceil\frac{a}{x}\rceil ⌈ x a ⌉ ,这个枚举量是 O ( A log A ) O(A\log A) O ( A log A ) 的,可以接受。
接下来,对于每个 ⌈ a x ⌉ \lceil\frac{a}{x}\rceil ⌈ x a ⌉ ,可能成为最大值的只有可能对应区间内的 h h h 最大的两个,但是这样就要求区间最大与次大,直接维护还是要带 log \log log 。如果我们把 l ≤ a ≤ r l\le a\le r l ≤ a ≤ r 的条件弱化为 a ≥ l a\ge l a ≥ l ,然后对于 a > r a>r a > r 的仍然当作现在枚举的 ⌈ a x ⌉ \lceil\frac{a}{x}\rceil ⌈ x a ⌉ 来算,发现并不影响结果,我们只需要在维护最大与次大时记录一个 i d id i d ,不要让最大与次大的 i d id i d 相同即可。
这样,我们要求的问题转化为 a ≥ l a\ge l a ≥ l 的 h h h 的最大与次大,这可以通过一个类似后缀 max \max max 的操作来线性预处理。
至此,我们在 O ( n + A log A ) O(n+A\log A) O ( n + A log A ) 的时间复杂度内解决了这个问题,突破了思维定势!
CF995F Cowmpany Cowmpensation
相比于前两题,就更像是一道套路的题目了,没有什么人类智慧难度。
考虑朴素的 dp,令 f u , i f_{u,i} f u , i 为以 u u u 为根子树内,u u u 的点权 ≤ i \le i ≤ i 的方案数。
考虑转移是什么,首先忽略 u u u 填的值,那么就是将所有子树的 f f f 进行点积,求出 g u , i g_{u,i} g u , i 表示 u u u 子树内,所有儿子节点的点权都 ≤ i \le i ≤ i 的方案数。
再考虑 u u u 填什么,我们钦定每个 g u , i g_{u,i} g u , i 中,u u u 的点权都选择 i i i ,这样不会算重,而 f u , i = ∑ j ≤ i g u , j f_{u,i}=\sum_{j\le i} g_{u,j} f u , i = ∑ j ≤ i g u , j 。
因此转移的本质是对一个点所有子节点的 dp 值进行点积,随后求一遍前缀和。
将 f u , i f_{u,i} f u , i 看作一个函数(注意不是生成函数),即考虑 F u F_u F u ,其中 F u ( x ) = f u , x F_{u}(x)=f_{u,x} F u ( x ) = f u , x 。容易发现每一次转移 F F F 的度数会 + 1 +1 + 1 ,因此最终 F F F 的度数 ≤ n \le n ≤ n ,因此只要记录 O ( n ) O(n) O ( n ) 个 F u F_u F u 的值,就可以在计算答案的时候插值出 F 1 ( d ) F_{1}(d) F 1 ( d ) 了。
ARC124E Pass to Next
考虑赋予 ∏ x i \prod x_i ∏ x i 实际意义,假设第 i i i 个位置有 x i x_i x i 个球,那么这个式子的意义就是每个位置选择一个球,选球的方案数。
先不考虑本质不同的方案,令 f i , 0 / 1 f_{i,0/1} f i , 0 / 1 表示考虑了前 i i i 个位置,最后一个位置是选择了自己原本的球 / 选择了上一个传过来的球的方案数。
此处,自己原本的球在往后传的过程中计算,上一个传过来的球在 i − 1 → i i-1\to i i − 1 → i 的转移时计算。
那么容易列出转移方程:
[ f i , 0 f i , 1 ] × [ ∑ x = 0 a i x ∑ x = 0 a i x ( a i − x ) ∑ x = 0 a i 1 ∑ x = 0 a i x ] = [ f i + 1 , 0 f i + 1 , 1 ] \begin{bmatrix}f_{i,0}&f_{i,1}\end{bmatrix}\times
\begin{bmatrix}
\sum_{x=0}^{a_i}x&\sum_{x=0}^{a_i}x(a_i-x)\\
\sum_{x=0}^{a_i}1&\sum_{x=0}^{a_i}x
\end{bmatrix}=\begin{bmatrix}f_{i+1,0}&f_{i+1,1}\end{bmatrix}
[ f i , 0 f i , 1 ] × [ ∑ x = 0 a i x ∑ x = 0 a i 1 ∑ x = 0 a i x ( a i − x ) ∑ x = 0 a i x ] = [ f i + 1 , 0 f i + 1 , 1 ]
此时还有两个问题:原问题是一个环 与 原问题 b b b 相同的只算一次。
对于第一个问题,可以破环为链,然后枚举破环为链割开的点选了什么球来计算。
对于第二个问题,发现如果所有点都向后传了至少一个,那么每个都少传一个最终的 b b b 是一样的,而如果有至少一个间隔没有往后传,那么一定没有另一个 b b b 序列与之相同,因此只需要在 dp 时再记录一维 0 / 1 0/1 0 / 1 表示是否有一个间隔出现过没有往后传的情况即可。
AGC016F Games on DAG
首先发现两枚棋子其实是两个独立的游戏,我们对于每一个为起点放一枚棋子求出 SG 后,只需要 1 , 2 1,2 1 , 2 节点的 SG 值不同那么就是先手必胜。
如果一个点的 SG 值 = x =x = x ,那么对于每个 y < x y< x y < x 他必须向至少一个 SG 值 = y =y = y 的点连边,而不能像任何一个 SG = x =x = x 的点连边,对于 SG > x >x > x 的点,是否连边都行。
考虑从大到小分层确定每个点的 SG,令 f ( S ) f(S) f ( S ) 表示已经确定了 S S S 点集的点相对 SG 值(因为我们是从大到小确定 SG 值的,所以并不能确定 SG 值具体是多少,但是最后一层 dp 到的点就可以看作 SG = 0 =0 = 0 的)的不同的连边方案。
转移时,枚举最后一层填 SG 最小 = x =x = x 的是哪个集合的点集,设为 s s s ,那么 t = S ∖ s t=S\setminus s t = S ∖ s 集合的点就是确定了的 SG > x >x > x 的点。
考虑转移的方案:
对于每个 u ∈ t u\in t u ∈ t 的点,都至少向 s s s 中的点连一条边,方案是 2 ∣ e u ∩ s ∣ − 1 2^{\mid e_u\cap s\mid}-1 2 ∣ e u ∩ s ∣ − 1 。
对于每个 u ∈ s u\in s u ∈ s 的点,都可以向 t t t 中的点任意连边,方案是 2 ∣ e u ∩ t ∣ 2^{\mid e_u\cap t\mid} 2 ∣ e u ∩ t ∣ 。
由于需要 1 , 2 1,2 1 , 2 的 SG 值不同,所以在转移时只需要保证 s s s 中不能同时出现 1 , 2 1,2 1 , 2 即可。复杂度 O ( 3 n ⋅ n ) O(3^n\cdot n) O ( 3 n ⋅ n ) 。
AGC016E Poor Turkeys
发现如果想让一直火鸡最后生存下来,那么必然会牺牲一些火鸡,并且对于一只火鸡,如果他最后能生存下来,那么必须牺牲的火鸡是确定的。
对于每一只火鸡 a a a ,我们想让他最后生存下来,那么倒序考虑,时刻维护一个集合 S = { a } S=\{a\} S = { a } ∪ \cup ∪ 必须牺牲的火鸡集合。如果出现了一对 ( x , y ) (x,y) ( x , y ) ,分如下情况考虑:
x ∈ S , y ∈ S x\in S,y\in S x ∈ S , y ∈ S ,那么两者在之后的操作中都是必须牺牲的或者就是 a a a ,但是这一次操作必须牺牲一个,所以直接导致 a a a 不可能生存。
x ∈ S , y ∉ S x\in S,y\not\in S x ∈ S , y ∈ S ,那么 x x x 在之后操作中有用,这一次不能牺牲,所以 y y y 只能牺牲,所以将 y y y 加入 S S S 。
x ∉ S , y ∉ S x\not\in S,y\not\in S x ∈ S , y ∈ S ,那么这一次操作对于 S S S 没有影响。
对于每一个火鸡 x x x 求出 S x S_x S x 后,考虑如何判断两只火鸡 x , y x,y x , y 能否同时生存,如果 x , y x,y x , y 分别都有可能最终生存,结论是 S x ∩ S y = ∅ S_x\cap S_y=\emptyset S x ∩ S y = ∅ 。考虑证明:
充分性:两者无交,所以每只火鸡最多只会影响到最终一只火鸡的状态,不会有重复,一定有解。
必要性:考虑上述加入元素到 S S S 中的过程,如果一对 ( x , y ) (x,y) ( x , y ) 满足原来 x ∈ S , y ∉ S x\in S,y\not\in S x ∈ S , y ∈ S ,导致 y y y 加入了 S S S ,那么连一条从 y → x y\to x y → x 的有向边,死火鸡的过程其实等价于在这张 DAG 上不断删点,如果 S x ∩ S y ≠ ∅ S_x\cap S_y\not=\emptyset S x ∩ S y = ∅ ,那么最终一定会有至少一个点 u u u 满足有 u → v u\to v u → v 与 u → w u\to w u → w 两条边,且 v ≠ w v\not=w v = w ,那么两条边上都要让 u u u 死一次,但是 u u u 只能死一次,所以不合法,因此 S x ∩ S y = ∅ S_x\cap S_y=\emptyset S x ∩ S y = ∅ 。
使用 bitset 维护每个 S x S_x S x ,最后数数的时候暴力枚举即可,时间复杂度 O ( n m + n 3 ω ) O(nm+\frac{n^3}{\omega}) O ( n m + ω n 3 ) 。
ARC117F Gateau
感觉没有铜牌难度啊。
首先考虑二分答案,暴力做法是破环成链,将每个限制转化为一段区间的和 ≥ \ge ≥ 或 ≤ \le ≤ 某个值。考虑对前缀和做差分约束即可,时间复杂度 O ( n 2 log A ) O(n^2\log A) O ( n 2 log A ) 。
考虑瓶颈在于每次都要使用 spfa 判断是否存在负环,我们希望能更快的判断负环。
观察到这张图其实就是上下两层,层间从下到上连边权为负的边,从上到下连边权为正的边,每个都都能往前连边权为 0 0 0 的边,第二层的头向第一层的尾边权为 0 0 0 的边,第一层的头向第二层的尾连边权为二分到的和的边。
负环的形态一定是如下三种之一:
直接从一对上下的点走一个二元环。
经过了从第一行头到第二行尾的边,此时一定是一个按照顺序上下交替的路径,起点和终点的方向没有限制。
经过了从第二行头到第一行尾的边,此时一定是一个按照顺序上下交替的路径,并且头尾都是从上往下的路径。
对于第一种情况,可以直接判断,对于后面两种情况,可以 dp 求解最小值,判断其是否 < 0 <0 < 0 ,即可做到 O ( n ) O(n) O ( n ) 判断是否存在负环。
综上,时间复杂度被优化为 O ( n log A ) O(n\log A) O ( n log A ) 。
P9746 「KDOI-06-S」合并序列
感觉是一道比较套路的题,但是我怎么没想出来。。。以下称 s [ l , r ] = ⊕ i = l r a i s[l,r]=\oplus_{i=l}^r a_i s [ l , r ] = ⊕ i = l r a i 。
首先考虑区间 dp,令 f i , j f_{i,j} f i , j 表示区间 [ i , j ] [i,j] [ i , j ] 能否被操作成为一个数。发现转移一定是 [ … ] … [ … ] … [ … ] [\dots]\dots[\dots]\dots[\dots] [ … ] … [ … ] … [ … ] ,其中三段 [ … ] [\dots] [ … ] 都是能被操作为一个数的区间,且三段的异或和 = 0 =0 = 0 ,直接转移复杂度爆炸。
考虑减少枚举的位置,我们枚举第一个段的右端点,即第一个 [ … ] [\dots] [ … ] 的 ] ] ] 位置,假设该位置为 k k k ,那么第一段的异或和 = s [ i , k ] =s[i,k] = s [ i , k ] ,我们要 check 是 ( k , j ] (k,j] ( k , j ] 能否找出两个合法的不交的区间,且第二个区间的右端点 = j =j = j ,使得两个区间的异或和 = s [ i , k ] =s[i,k] = s [ i , k ] 。
观察到一个性质,如果 [ l , r ] [l,r] [ l , r ] 内能找到两个不交的合法区间,第二个区间的右端点 = r =r = r ,且两段区间的异或和 = s =s = s ,那么对于 l ′ < l l'< l l ′ < l ,[ l ′ , r ] [l',r] [ l ′ , r ] 一定也能找到。
所以考虑记 g i , w g_{i,w} g i , w 表示以 i i i 为右端点,找到两段合法区间异或和 = k =k = k 的最右边的左端点,即一个 … [ … ] … [ … ] \dots[\dots]\dots[\dots] … [ … ] … [ … ] 这样一个子结构的最右左端点位置。
那么在转移 f f f 时只需要枚举 i , j , k i,j,k i , j , k ,然后判断 g j , s [ i , k ] g_{j,s[i,k]} g j , s [ i , k ] 是否 > k >k > k 即可。此时 f f f 的转移已经做到 O ( n 3 ) O(n^3) O ( n 3 ) 了,但是我们仍然无法快速计算 g g g 。
考虑再记录一个 h i , w h_{i,w} h i , w 代表寻找一个 i i i 左边的区间,且这个区间异或和 = w =w = w 的最右边的左端点,即 [ … ] … [\dots]\dots [ … ] … 这样一个结构,以 i i i 为右端点,左边区间异或和 = w =w = w 的最右左端点。
那么在转移 g g g 时,考虑枚举 … [ … ] … [ … ] \dots[\dots]\dots[\dots] … [ … ] … [ … ] 种右边那个合法区间的左端点,即对于 g i , w g_{i,w} g i , w ,枚举 j j j ,那么 g i , w ← h j , s [ i , j ] ⊕ w g_{i,w}\leftarrow h_{j,s[i,j]\oplus w} g i , w ← h j , s [ i , j ] ⊕ w 。
而 h h h 是可以在求出 f f f 后直接刷表更新的,综上所有 dp 数组的转移复杂度均为 O ( n 3 ) O(n^3) O ( n 3 ) 或 O ( n 2 w ) O(n^2w) O ( n 2 w ) ,注意一下转移顺序即可。
P6682 [BalticOI 2020 Day1] 染色
想了好久啊,感觉那个人类智慧的做法确实不好想。
朴素的想法是直接二分,每次先把位置移动到 1 1 1 ,然后往后移动 m i d mid m i d 的距离,这样的询问次数是 2 log n 2\log n 2 log n ,无法通过,发现瓶颈在于每次想要二分一个值时都需要从 1 1 1 开始移动。
如果我们能够找到一种移动方法,使得每次无论二分到哪个值,都能够成功的走过这个距离,那么就能够做到 log n \log n log n 次询问了。
考虑极限情况,每次都往上二分,即 n 2 , 3 n 4 , 7 n 8 , … \frac{n}{2},\frac{3n}{4},\frac{7n}{8},\dots 2 n , 4 3 n , 8 7 n , … 的情况。
接下来有一个非常人类智慧的做法,考虑倒序确定,假设最后会到达 1 1 1 ,那么倒序地左右交替跳,由于倒序情况下每次跳的长度都比上一次短,所以一定不会跳出界。
考虑如果有一次二分没有顶到上界,那么相当于整体的向左或向右平移,依旧并不会跳出界。因此我们可以直接跳来二分了,询问次数 log n \log n log n 。
CF1622F Quadratic Set
结论题也算逆天题嘛。。。可能这才是真的逆天吧!
首先考虑 n n n 是偶数的情况,设 m = n 2 m=\frac{n}{2} m = 2 n ,那么有如下式子:
∏ i = 1 n i ! = ∏ i = 1 2 m i ! = ∏ i = 1 m ( 2 i − 1 ) ! ( 2 i ) ! = ∏ i = 1 m ( 2 i − 1 ) 2 ⋅ 2 i = 2 m ⋅ m ! ⋅ ( ∏ i = 1 m ( 2 i − 1 ) 2 ) \prod_{i=1}^n i! =\prod_{i=1}^{2m} i! =\prod_{i=1}^m (2i-1)!(2i)! = \prod_{i=1}^m (2i-1)^2\cdot 2i=2^m\cdot m!\cdot(\prod_{i=1}^m (2i-1)^2)
i = 1 ∏ n i ! = i = 1 ∏ 2 m i ! = i = 1 ∏ m ( 2 i − 1 ) ! ( 2 i ) ! = i = 1 ∏ m ( 2 i − 1 ) 2 ⋅ 2 i = 2 m ⋅ m ! ⋅ ( i = 1 ∏ m ( 2 i − 1 ) 2 )
如果 m m m 是奇数,那么删除一个 2 2 2 ,删除一个 m m m 后,式子变成 2 m − 1 ⋅ ( ∏ i = 1 m ( 2 i − 1 ) 2 ) 2^{m-1}\cdot(\prod_{i=1}^m (2i-1)^2) 2 m − 1 ⋅ ( ∏ i = 1 m ( 2 i − 1 ) 2 ) ,是完全平方数。
如果 m m m 是偶数,那么删除一个 m m m 后,式子变成 2 m ⋅ ( ∏ i = 1 m ( 2 i − 1 ) 2 ) 2^m\cdot(\prod_{i=1}^m (2i-1)^2) 2 m ⋅ ( ∏ i = 1 m ( 2 i − 1 ) 2 ) ,是完全平方数。
因此对于 n n n 为偶数是,答案 ≥ n − 2 \ge n-2 ≥ n − 2 ,而对于 n n n 是奇数,再删掉一个 n n n 可以变为 n n n 是偶数的情况,因此答案 ≥ n − 3 \ge n-3 ≥ n − 3 。
接下来就比较套路了,对于每一个质因数随机一个 hash 值,做异或哈希,对于删除 0 , 1 , 2 0,1,2 0 , 1 , 2 个数是容易判的,删除三个数的直接构造即可。复杂度 O ( n log n ) O(n\log n) O ( n log n ) 。