ARC217
AtCoder Regular Contest 217
闲话
\(\text{Perf. } \color{red}{2898}\),我爱数数,数数爱我。
能看出来比较大的问题还是在最优化题目上面,最优化的重心很多时候不是找到等价结构,而是找到了之后该如何利用特殊性质去辅助你简化地求题目问的东西。
很多时候能观察到主要结构并且摸清楚 key observation,但是并不真正理解这个结构和所求的统计量之间的逻辑关系,导致一旦开始想做法就容易漏掉并不困难的,从所求统计量那一侧延申出来的关键观察,开始莽大东西上去维护,又导致问题复杂化了。
A (位运算、Trie 树、构造、*1000):
没动脑子分析他们说的循环和对称性什么的,不需要这么做。
考虑直接将这 \(n\) 个数插入到 Trie 内,维护已经构造出序列的前缀异或和。
每次找到当前 Trie 树内未被删去的,与前缀异或和异或起来最小的数填到这一位,再将其从 Trie 树中删去,重复 \(n\) 次即可得到答案序列。
证明就是:位置为 \(j\) 的元素,如果异或使得某一位上为 \(1\) 那么这个贡献的系数为 \(n - j + 1\),这个贡献的一个后缀可能会被后面这一位上为 \(1\) 的值来回 flip。但就算后面能被 flip 回来,将其交换到被 flip 的前一位必定不劣。直接贪心必定就是对的。
时间复杂度 \(\mathcal{O}(n \log V)\)。
B (组合数学、*1800):
令 \(S\) 表示排列 \(P\) 中所有前缀最大值组成的集合。
假设 \(P\) 确定了那么 \(S\) 也确定了,令 \(W(S) = \sum_{i \in S} 2^{P_i-1}\)。
当我们进行一次操作将某一个 \(k\) 移动到前面时,\(k\) 成为了前缀最大值,而 \(1,2,3,\dots,k-1\) 绝不可能成为前缀最大值。
所以 \(W(S)\) 增加了 \(2^{k-1}\),减少了 \(\sum_{j=1}^{k-1} 2^{j} \lt 2^{k-1}\),那么每次调整 \(W(S)\) 必定递增。
又因为每次选择不为前缀最大值的最小元素 \(W(S)\) 就只会 \(+1\),所以至多操作次数就是 \(2^{n}-1-W(S)\)。
那么我们只需要求出所有 \((n - k)!\) 个可能排列对应的 \(W(S)\) 之和就好了。
这个可以直接拆每个值成为前缀最大值所带来的贡献,那么有:
其实问题的核心就是求出 \(C(x)\) 表示令不在 \(A_{[1,k]}\) 内的任意一个元素 \(x\) 成为前缀最大值的合法排列数量,求出这个就好做了。
如果 \(n\) 出现在 \(A_1,A_2,\dots,A_k\) 中那么整个序列的 \(S\) 已经被固定了,提前处理出 \(A_{[1,k]}\) 中每个值是否为前缀最大值,对于这 \(k\) 个值之外的数他们必定不为前缀最大值,所以 \(W(S)\) 就是 \(\sum_{i=1}^{k} [A_i \in S] 2^{A_i-1}\)。最终的答案就是 \((n-k)! \times W(S)\)。
否则,求出 \(t = \max\limits_{1 \le i \le k} A_i\),则任意一个小于等于 \(t\) 的没有在 \(A_{[1,k]}\) 内出现的值都不可能成为前缀最大值了。
可以先求出 \(A_{[1,k]}\) 对应的前缀最大值贡献,接下来我们考虑 \([k + 1, n]\) 部分的前缀最大值贡献。
需要排列的这个后缀的值域是 \([n] \setminus A_{[1,k]}\),对于一个 \(y \in [n] \setminus A_{[1,k]}\) 如果它是前缀最大值那么它必定在所有大于它的元素之前,又因为它大于 \(\max\limits_{1 \le i \le k} A_i\) 所以所有大于它的元素都在这个后缀内。所以一共有 \(n-y + 1\) 个这样的数,它排最前的概率也就是 \(\frac{1}{n-y+1}\)。排列数就是 \((n-k)! \times \frac{1}{n-y+1}\)。这一部分也是可以 \(\mathcal{O}(n)\) 求的。答案就是将上面两部分加在一起。
时间复杂度 \(\mathcal{O}(n)\)。
C (区间DP、组合数学、*2100):
场上的做法,比较的无脑。
因为每个人买的一定是能买所有物品中最贵的,所以可以先将所有物品从小到大排序方便后面分析。
发现求恰好 \(k\) 是比较困难的,但求至少 \(k\) 是简单的,它只对值域上一个前缀有约束。
具体地说,如果要求至少 \(k\) 个物品被买走,等价于对 \(i=1,2,3,\dots,k\),至少有 \(k-i+1\) 个人的预算 \(\ge A_i\)。
证明这个观察。该结论的必要性是显然的,充分性你考虑一个人进来买走一件物品他就消耗了一个预算 \(\ge A_i\) 的名额也删掉了一件对应范围内的物品,可以归约到 \(k-1\) 的情形,所以必定是充分的。从二分图的角度去思考就是每个人向一个前缀的限额对应的的点连边,霍尔定理不难证明其充分性。
到这里就可以 DP 了。
枚举 \(k\),令 \(f(i,j)\) 表示从后往前考虑 \(A_k,A_{k-1},\dots,A_1\),目前已经确定了有 \(j\) 个人 \(\ge A_i\),并且满足前面所有限制的方案数。
转移考虑枚举有 \(c\) 个人落在区间 \([A_{i-1},A_i)\) 内,那么转移 \(f(i+1,j) \times \binom{n-j}{c} \times (A_i-A_{i-1})^c \to f(i,j+c)\)。
上面转移要确保约束成立,也即 \(k-i+1 \le j + c\)。
最后求答案的时候考虑差分一下 \(k\) 和 \(k+1\) 就能求出恰好 \(k\) 的答案。
枚举 \(k\) 是 \(\mathcal{O}(n)\) 的,转移是 2D1D 的,总时间复杂度 \(\mathcal{O}(n^4)\)。
直接刻画选取的过程是困难的,我们考虑从最终购买的物品集合入手。
设 \(f(l,r)\) 表示用恰 \(r-l+1\) 个人将区间 \([l,r]\) 买空,并且强制限定 \(r+1\) 不被买的方案数。
可以枚举中间点合并区间转移:\(f(l,r)=\sum_{k=l}^{r} \left(f(l,k-1) \times f(k+1,r) \times \binom{r-l}{k-l} \times (A_{r+1}-A_{k})\right)\)。
第一个系数的组合意义是归并 \([l, k - 1]\) 和 \([k + 1, r]\) 的方案数,第二个系数是 \(k\) 对应这个人的预算选取方案。
但这个状态并没有办法涉及到所有情形:因为当一个人的预算小于 \(A_1\) 他什么也买不了,所以如果考虑的是一个前缀那么会数漏一些方案。设 \(g(r,i)\) 表示考虑从 \(1\) 开始的前缀 \([1,r]\),一共用了 \(i\) 个人将这个前缀删空的方案数。
转移和上面是类似的,枚举中间点然后从 \(g(k-1,j)\) 和 \(f(k+1,i-j-1)\) 合并而来。
这里需要额外加一种转移就是新加进来一个预算比当前剩余最小值更小的人,他啥都买不了。
最终只需要将前缀的情形和区间的情形合并起来即可。
具体地说,因为恰好 \([1,x]\) 这个前缀被删空,所以 \(x+1\) 必定未被删,整个序列被分割为 \([1,x]\) 和 \([x + 2, n]\) 这两段。枚举前面一段用的人数 \(k\),那么问题恰好能从前缀 \(k\) 人和后缀 \(n - k\) 人的子问题合并而来:
- 前缀 \(k\) 人:直接对应了 \(g(i,k)\)。
- 后缀 \(n - k\) 人:可以另外设 \(h(i,j)\) 表示后缀 \(A_{[i,n]}\) 中恰好买了 \(j\) 件商品的方案数,因为是后缀所以不可能有无效购买,转移就是 \(h(i,j) \leftarrow h(i+1,j) + \sum_{t=i}^{n} \left(f(i,t) \times h(t+2,j-(t-i+1)) \times \binom{j}{t-i+1}\right)\),组合意义显然。
最终统计答案时直接枚举分界点,合并每一种可能的前后缀选法即可得到答案。
时间复杂度 \(\mathcal{O}(n^3)\)。
D (DP优化、双端队列、并查集、*2500):
首先有一个 \(\mathcal{O}(nm)\) 的做法:对 \(k=0,1,2,3,\dots,n\),从前往后模拟一遍。
没法优化,考虑换维:设 \(f(i,j)\) 表示从 \(i\) 开始处理 \(A_{[i, n]}\) 的购买情况,此时金额剩余为 \(j\) 对应的已选物品价值。
那么对于 \(j \ge A_i\) 的情形他会从 \(f(i + 1, j - A_i) + A_i\) 转移过来,否则会从 \(f(i+1,j)\) 转移。
这个时候你考虑将 \(+A_i\) 当作一个整体的 tag 去处理,则问题变成了对一个前缀单独打 \(-A_i\) 的 tag。
也就是你画出转移图,会发现从 \(f(i+1,*)\) 到 \(f(i,*)\) 的转移中,对 \(\le A_i\) 的部分先从 \(f(i + 1)\) 的对应位置继承过来,再整体打一个减去 \(A_i\) 的 tag。因为每次都是扩展出一个新的前缀,所以一旦进入这个前缀就不可能又被单独分裂出来,那么直接利用并查集维护前缀。
具体讲一下每次如何确定打 \(-A_i\) 前缀的右端点具体在哪,可以从前往后推,依题意有 \(R_{i+1} \leftarrow \min(R_i, \max\{A_i, C_i - A_i\})\),从而 \(\mathcal{O}(n)\) 地直接递推求出每轮对应的右端点 \(R_i\)。
其实也可以利用双端队列维护有 tag 和无 tag 的两种转移方式,类 BFS 序处理 DP 转移对应的自动机即可做到严格线性。
赛时就是没想到前缀的性质,非要写那个李超树维护分段函数写不清楚,合着白白浪费快半个小时/kk
时间复杂度 \(\mathcal{O}(m \alpha(n) + n)\)。
E (概率论、组合数学、*2600):
好像是第一道自己场切的 ARC E 捏。
设 \(T_k\) 表示第 \(k\) 次加入点后得到的树,初始为 \(T_0\)。同理 \(\text{dis}_{i}(u,v)\) 表示点 \(u,v\) 在 \(T_i\) 上的最短距离。
考虑求出一开始 \(n\) 个点的树的答案 \(h_0\),每次加一个点,增量法递推出最终的答案 \(h_k\)。
假设现在进行到第 \(i\) 步那么他现在有 \(n + i - 2\) 条边,从这 \(n+i-2\) 条边中等概率随一条边操作。
这必定是要拆贡献的,贡献可以分为互不影响的两部分:
- 旧顶点之间的影响,假设这条边为 \((u,v)\),那么 \(x - u - v - y\) 这样的点对 \((x,y)\) 会受影响。
- 新的顶点 \(n+i\) 到所有旧的顶点的距离之和。
第一类贡献
每一对这样的 \(x,y\) 之间距离会加上 \(1\),所以总共的增量就是这种点对的期望数量。
拆一下贡献,从固定 \((x,y)\) 的角度看就是他们路径 \(p(x,y)\) 上某条边被等概率随机选中的概率。
这个是 \(\frac{\text{dis}(x,y)}{n+i-2}\),所以这样加一个点产生的 \(\text{dis}_{i}(x,y)\) 就是:
合并同类项可以得到就是 \(\text{dis}_{i-1}(x,y)+\frac{\text{dis}_{i-1}(x,y)}{n-i+2}\)。
然后你可以对所有点对求和得到最终整个的递推式:
令 \(T_{i-1}\) 对应的第一类贡献为 \(f_{1,i-1}\),则 \(f_{1,i} = h_{i-1} \times \left(1 + \frac{1}{n-i+2}\right)\)。
第二类贡献
假设 \(n + i\) 加到 \(e=(u,v) \in T_{i-1}\) 中间。
任何一个旧的点 \(x\) 到新加入的顶点 \(n+i\) 的距离是 \(\text{dis}_{i}(x,n+i) = \min\left(\text{dis}_{i-1}(x,u),\text{dis}_{i-1}(x,v)\right)+1\)。
距离的期望值就是 \(E[\text{dis}_{i}(x,n+i) \mid T_{i-1}]=\frac{1}{n+i-2} \sum_{e = (u,v) \in T_{i-1}} (\min\left(\text{dis}_{i-1}(x,u),\text{dis}_{i-1}(x,v)\right)+1)\)。
然后对取 \(\min\) 的部分可以直接把 \(T_{i-1}\) 提起来以 \(x\) 为根。
对任意一条边 \(e=(u,v)\),设 \(u\) 恰为 \(v\) 的父节点(反之亦然),那么有 \(\text{dis}(x,u) \lt \text{dis}(x,v)\),\(\min\) 中的取值就是 \(\text{dis}(x,u)\)。
那么求和式子就直接变为 \(\sum_{y \ne x} \text{dis}(x,\text{fa}(y))\)。可以理解为把所有可能的 \(n+i\) 出现位置放到边上,然后每条边挂在深度较浅那个点下面。又因为 \(\text{dis}(x,\text{fa}(y))=\text{dis}(x,y)-1\) 所以可以进一步地将上面式子化简为 \(\sum_{y \ne x} \text{dis}(x,y) - (n + i - 2)\)。
可以先设 \(g_{i-1}(x) = \sum_{y \in T_{i-1}} \text{dis}_{i-1}(x,y)\),那么上面的式子就是 \(g_{i-1}(x) - (n + i - 2)\)。
所以要求的那个距离的期望就是 \(E[\text{dis}_{i}(x,n+i)\mid T_{i-1}]= \frac{g_{i-1}(x)-(n+i-2)}{n+i-2} + 1\)。
进一步对所有 \(x \in T_{i-1}\) 求和可以得到:
又有 \(\sum_{x=1}^{n+i-1}g_{i-1}(x)=\sum_{1 \le x, y \le n+i-1} \text{dis}(x,y) = 2 h_{i-1}\)。
所以第二部分的答案就是 \((n+i-1) + \frac{2h_{i-1}-(n+i-1)(n+i-2)}{n+i-2}\),即 \(f_{2,i}=(n+i-1) + \frac{2h_{i-1} - (n+i-1)(n+i-2)}{n+i-2}\)。
那么你把两部分加起来就可以得到 \(h_i = h_{i-1} \times \left(1 + \frac{1}{n+i-2} \right) + (n + i - 1) + \frac{2h_{i-1} - (n+i-1)(n+i-2)}{n+i-2}\)。
进一步化简之后你就得到 \(h_i = h_{i-1} \times \frac{n+i+1}{n+i-2}\)。所以 \(h_i = h_0 \times \left(\prod_{j = 2} ^ {k+1} \frac{n+j}{n+j-3} \right)\)。
其实上面式子很多地方可以直接消掉,但为了对上组合意义还是把最开始的形式写出来了,所以可能有点大,实际推的时候还好。
这个是初中数学题,可以化为 \(h_k = h_0 \times \frac{(n+k-1)(n+k)(n+k+1)}{n(n-1)(n+1)}\)。
至于 \(h_0\),你考虑拆每一条边 \(e=(u,v)\) 的原始贡献,任取一点为根(假设此时 \(\text{fa}(v) = u\))那么它被经过的次数就是 \(\text{size}(v) \times (n - \text{size}(u))\),对这个求和即可。
时间复杂度 \(\mathcal{O}(n)\)。
浙公网安备 33010602011771号