随机乱做 Part 3

「CF1527D」MEX Tree(分类讨论 + 容斥)

题面

路径上的点的 \(\mathrm{MEX}=i\) 等价于有点 \(0\sim i-1\),并且没有点 \(i\)。我们可以直接处理出 \(ans_i\) 表示存在点 \(0\sim i\) 的路径条数。这个可以考虑以 \(0\) 为根,现在包含 \(0\sim i\) 的链的形状,即一端为 \(0\) 或者两端在 \(0\) 的两个不同的子树内,贡献可以直接计算。但是分类讨论有一点/tuu

容斥一下,\(ans_{i-1}-ans_i\) 就是 \(\mathrm{MEX}=i\) 的答案。

代码:https://pastebin.ubuntu.com/p/xTvjbxFDTX/

「CF1523D」Love-Hate(随机化 + 高维后缀和)

题面

又一次败在了随机化的题上……

因为有不少于 \(\lceil\frac{n}{2}\rceil\) 个人在最终答案里,所以如果随机 \(i\) 个人,使得他在最终答案里,那么错误的概率将会是 \(\frac{1}{2^i}\)。所以问题转化为:一个人喜欢的货币中,最多选出多少个使得有不少于 \(\lceil\frac{n}{2}\rceil\) 个人都喜欢它们。

因为 \(1\le p\le 15\),所以可以考虑状压 DP。设 \(f_S\) 表示喜欢集合 \(S\) 中所有货币的人的数量,转移就是一个高维后缀和。求答案直接在 \(f_S\ge \lceil\frac{n}{2}\rceil\)\(S\) 中找 \(\rm{popcount}\) 最大的 \(S\) 就行了。

感觉这种随机化基本想不到啊……还是要多见见。

代码:https://pastebin.ubuntu.com/p/cxKvrx53ws/

「CF1523E」Crypto Lights(期望转概率 + 组合数学)

题面

\(p_i\) 为最终开了 \(i\) 盏灯的概率,那么 \(E=\sum\limits_{i=1}^n p_ii\)

直接求并不好求,我们考虑化一下式子:\(E=\sum\limits_{i=1}^n\sum\limits_{j=i}^n p_j\),这样如果设 \(s_i=\sum\limits_{j=i}^n p_j\),那么 \(E=\sum\limits_{i=1}^n s_i\)

考虑 \(s_i\) 的意义,是最终开了 \(\ge i\) 盏灯,那么就相当于前面 \(i-1\) 盏灯没有冲突。这个很好求,相邻两盏灯之间的间隔都要 \(>k-1\),所以方案数就是 \(\binom{n-(k-1)(i-1)}{i}\),概率就还需要除一个 \(\binom{n}{i}\)

那么就做完了!

代码:https://pastebin.ubuntu.com/p/yfbDrjMWR3/

「洛谷 P5574」[CmdOI2019]任务分配问题(分治决策单调性优化 DP + 莫队状指针移动)

题面

很明显的暴力 dp:设 \(f_{i,j}\) 表示前 \(i\) 个数分成了 \(j\) 段的最小无序度之和。转移可以枚举上一段的起点在哪里。

对于划分区间的问题,需要长个心眼:是否满足决策单调性(四边形不等式),即 交叉 \(\le\) 包含?

发现这道题中确实如此,证明可以考虑讨论一下 一个产生贡献的点对中 的 两个点 在大区间中的位置。此处略去。

那么就可以愉快地跑分治决策单调性了!指针的移动可以像莫队那样子做(注意初始化 \(L=1\)),复杂度可以证明是正确的。

代码:https://pastebin.ubuntu.com/p/HWNwYYBTjt/

「CF1499F」Diameter Cuts(树形 DP)

题面

直径可以 DP 求,那么和直径相关的量也应该想到 DP。

\(f_{u,i}\) 表示 \(u\) 子树内连接 \(u\) 的最长链是 \(i\),且满足条件的方案数。

转移时枚举每条边 \((u,v)(v\text{\ is a son of } u)\) 是否断开:

  • 若断开,则 \(f_{u,i}\leftarrow f_{u,i}\times\sum\limits_{j=0}^k f_{v,j}\)
  • 若不断开,那么 \(f_{u,\max(i,j+1)}\leftarrow f_{u,i}\times f_{v,j}(i+j+1\le k)\)

答案即为 \(\sum\limits_{i=0}^k f_{1,i}\)

代码:https://pastebin.ubuntu.com/p/y4t6yVp8hB/

「CF1499E」Chaotic Merge(DP)

题面

\(f_{i,j,0/1}\) 表示 \(x\) 匹配到第 \(i\) 位,\(y\) 匹配到第 \(j\) 位,最后一位是 \(x_i/y_j\) 的方案数。

转移可以直接看倒数第二位是什么。

注意新开一个串的情况需要单独讨论,需要从 \(f_{0,j,1}/f_{i,0,0}\) 转移过来,而这些需要预处理。

代码:https://pastebin.ubuntu.com/p/QRBTGXnxBd/

「CF1572B」Xor of 3(构造)

题面

容易发现操作不会改变整个序列的异或和,所以如果有解,那么原序列异或和一定为 \(0\)

考虑如果 \(n\) 是奇数,那么可以先操作 \(n-2,n-4,\dots,3,1\) 来使得 \(a_n=a_{n-1},a_{n-2}=a_{n-3},\dots,a_3=a_2,a_1=0\),然后再反过来操作就可以得到全 \(0\)

如果 \(n\) 是偶数,那么找一个异或和为 \(0\) 的长度为奇数的前缀,前后分别来做 \(n\) 是奇数的构造就可以了。

代码:https://pastebin.ubuntu.com/p/SyrPsNwWbG/

「CF1585F / CF1571F」 Non-equal Neighbours & 「ARC115E」LEQ and NEQ(容斥 + 单调栈优化线性 DP)

题面

首先考虑容斥一下,假设有若干个 \(b_i=b_{i+1}\),那么就相当于把序列分成了一堆相等的段,段与段之间不一定不同。

那么答案就是 有 \(n\) 段的答案 \(-\)\((n-1)\) 段的答案 \(+\)\((n-2)\) 段的答案 \(\cdots\pm\)\(1\) 段的答案 \(\mp\)\(0\) 段的答案。

其实这个东西等价于:

  • \(n\) 是奇数时,答案为 分成奇数段的 \(-\) 分成偶数段的;
  • \(n\) 是偶数时,答案为 分成偶数段的 \(-\) 分成奇数段的。

那么可以考虑设 \(f_{i,0/1}\) 表示填完了 \([1,i]\),分成了偶数段 / 奇数段的答案。

转移:\(f_{i,0/1}=\sum\limits_{j=0}^{i-1}f_{j,1/0}\times\min\limits_{k=j+1}^i\{a_k\}\)

暴力做是 \(\mathcal{O}(n^2)\) 的。

看到这种区间 \(\min\) 的转移形式,需要联想到单调栈。维护一个严格递增的单调栈,那么设 \(x\)\(i\) 左边第一个小于 \(a_i\) 的位置,则有 \(f_{i,0/1}=f_{x,0/1}+a_i\times\sum\limits_{j=x}^{i-1}f_{j,1/0}\)。因为对于 \(1\sim x-1\) 的所有 \(y\) 转移到 \(i\) 的贡献为 \([y+1,i]\) 中的 \(\min\),这和 \([y+1,x]\) 中的 \(\min\) 一样,即贡献一样。所有这些贡献全部转移到了 \(f_{x,0/1}\),所以可以直接继承过来。

那么只需要维护一下分成 偶数段 / 奇数段 的前缀和就行了。

代码:https://pastebin.ubuntu.com/p/bGYQJvMgjd/

「CF1578L」Labyrinth(Kruskal 重构树 + 结论)

题面

首先肯定是建出最大生成树。

然后考虑,如果当前身体宽度比某些边大,那么这些边其实可以被理解为已经断掉了。

那么有一个结论:一条边如果断掉了,那么它的子树内的糖果一定已经全部被吃过了。证明显然。

于是就可以在建树的时候递推答案,在 先左子树后右子树 和 先右子树后左子树 中的答案取 \(\max\),这个“答案”其实就是 需要走完一个子树的最大初始身体宽度和当前边权取 \(\min\) 后减去还没走的子树内的糖果数量。

具体可以见代码理解。

代码:https://pastebin.ubuntu.com/p/nD7bZQfQ4M/

「CF1497E2」Square-free division (hard version)(转换枚举量 + 双指针 + DP)

题面

首先可以把每个数的平方因子除掉,很明显这样对答案没有影响。

\(f_{i,j}\) 表示前 \(i\) 个修改 \(j\) 次最多分了几段,转移的时候需要一个辅助数组 \(mx_{i,j}\) 表示以 \(i\) 结尾,修改 \(j\) 次能到达的满足条件的最远端点,那么 \(f_{i,j}\leftarrow\min\limits_{l=0}^j\{f_{mx_{i,l}-1,j-l}+1\}\)

考虑怎么求这个 \(mx_{i,j}\)。一个性质是在 \(j\) 不变的情况下,\(mx_{i,j}\) 随着 \(i\) 的递增而不降。那么就可以通过双指针来求。

注意有点卡常,需要预处理出每个数去掉平方因子后的结果。

代码:https://pastebin.ubuntu.com/p/ZgZzp8tHdT/

posted @ 2022-10-03 20:36  csxsi  阅读(19)  评论(0编辑  收藏  举报