近期总结2024.2.8
CF1491H Yuezheng Ling and Dynamic Tree
题意:一棵 \(1\) 为根的树,给出没个点的父亲 \(a_i\)。维护 \(m\) 次操作:给出 \(l,r,x\),修改 \(\forall i\in[l,r],\space a_i\gets \max(a_i-x,1)\);或者给出 \(x,y\),查询 \(x,y\) 在树上的 lca。\(1\le n,m\le 10^5\)
考虑我们需要动态维护一棵树,且父亲编号支持区间减法,不能用线段树等数据结构。
考虑分块,每 \(B\) 个为一块。每个点处理出该点不断跳父亲,跳出所在的块后到达的点,记为 \(f_i\)。那么,查询便很容易:两个点轮流往上跳,若不在同一块则较深的点网上跳出所在的块,若在同一块则判断跳出块后是否跳到同一点,若是则在块内暴力跳,若不是则仍然执行跳出块的操作。
考虑修改怎么维护。依然按照“整块标记,散块暴力”的思想。对于散块,我们可以暴力地更新 \(a_i\) 和 \(f_i\)。对于整块,不难发现,一个整块被修改 \(B\) 次后,块内每个点跳一次就能跳出来。因此,我们记录每个块修改时减少的数字和,若 \(\ge B\) 则说明每个点跳一次就能跳出来,否则仍然暴力更新。
一个块至多被暴力更新 \(O(B)\) 次,每次更新遍及每个点,共 \(n\) 个点,时间是均摊的,总时间 \(O(nB)\)。
复杂度 \(O((n+q)B+q\cdot \frac{n}B)\),取 \(B=\sqrt n\) 得到 \(O((n+q)\sqrt n)\)。
CF1392H ZS Shuffles Cards
题意:有 \(n+m\) 张牌,其中 \(n\) 张牌分别标有数字 \(1,2,...,n\),另外 \(m\) 张是 joker。一开始打乱这些牌,然后不断进行以下流程:
-
随机抽取一张牌。
-
若该牌是数字牌,则将对应数字加入集合 \(S\),然后移除这张牌;若是 joker,则将所有被移除的牌重新加入牌堆,若此时 \(S\) 中包含 \(1,2,...n\) 所有数,则终止游戏。
问期望抽牌多少次,模 \(998244353\)。 \(1\le n,m\le 2\times 10^6\)
考虑到每次抽取到 joker 会重新刷新牌堆,我们称此时游戏结束了一轮。
不难发现,期望抽牌数 \(=\) 期望轮数 \(\times\) 每轮期望抽牌数。
每轮期望抽牌数是容易求的,考虑枚举第一张 joker 的位置,然后组合数相除,乘以 \(i\)。
关键是期望轮数。考虑 Min-Max 容斥:
由于 \(1,2,...,n\) 每个数是一样的,因此我们只需要枚举 \(|S|\)。
\(E(\min_{i\in S}(t_i))\) 指 \(S\) 中的任意一张牌第一次被抽取期望是第几轮。根据经典方法,我们只需要求出每轮抽取出 \(S\) 中任意一张牌的概率。
考虑 \(S\) 中位置最靠前的一张牌和第一张 joker 的位置,需要计算的概率为前者比后者更靠前的概率,两者分别有 \(|S|\) 和 \(m\) 张,去掉其他牌影响后,相当于这 \(|S|+m\) 张牌任意排列,使得第一张为 \(S\) 中的牌的概率,为 \(\frac{|S|}{|S|+m}\)。
那么期望轮数编号即为 \(\frac{|S|+m}{|S|}\),时间复杂度 \(O(n+m)\)。
CF1188D Make Equal
题意:有 \(n\) 个数 \(a_{1...n}\),每次可以给其中一个数加上 \(2\) 的非负整数次数幂,求最少操作次数。 \(1\le n\le 10^5,\space 0\le a_i\le 10^{17}\)
设最终每个数都变成了 \(x\),那么操作次数为 \(\sum\limits_{i=1}^n \text{popcount}(x-a_i)\)。减法很烦,令 \(t=\max\limits_j\{a_j\},\space b_i=t-a_i\),然后 \(x'=x+t\),则原式变为 \(\sum\limits_{i=1}^n \text{popcount}(x'+b_i)\)。
现在的问题变为选择一个 \(x'\),然后求上式的最小值。
考虑 dp,设 \(f[i,j]\) 表示已经考虑了 \(x'\) 的前 \(i\) 位,\(a_{1...n}\) 中有 \(j\) 个数加上 \(x'\) 后向下一位进位,前 \(i\) 位产生的最小代价之和。
考虑从 \(f[i-1,]\) 转移到 \(f[i,]\),注意到如果前 \(i-1\) 位中,有 \(j\) 个数进位,必定是 \(n\) 个数每个数取出其前 \(i-1\) 位,组成一个新数后,最大的那 \(j\) 个。
我们按照这个新数为键值排序,然后枚举 \(j\)。考虑动态维护当前 \(j\) 条件下,有多少个 \(00,01,10,11\),然后直接转移即可,时间复杂度 \(O(n\log a)\)。