Hey Gift:爱是一场浩大的冒险
P11928 [PA 2025] 子序列 / Podciągi
我咋啥都不会做。
考虑容斥,首先序列本质不同子序列数是一个简单的 dp。为了支持带修,我们不要用 \(f_{lst}\) 辅助转移那种方法,而是用草坝牛 dp 01 串本质不同子序列数类似的方法。具体来说,\(f_{i,j}\) 表示前 \(i\) 个字符,以 \(j\) 结尾的本质不同子序列数,那么:
这显然可以 ddp。
然后考虑我们怎么算有多少个子序列出现了恰好一次。容易想到一个充要条件:我们考虑贪心地匹配它,那么每个字符后面到下一个字符之间都不能有第二个这个字符。
考虑怎么计数这种子序列。它虽然不太方便写成一个线性递推的形式,但我们发现它的判定对分治结构非常友好,而且不需要考虑算重等计数问题,直接数就完了。带修的分治考虑上线段树,\(f_{a,b}\) 表示线段树上某节点 \(a\) 开头 \(b\) 结尾,恰好出现一次的子序列数量即可。
合并是简单的。因为左侧的 \(b\) 一定是最后一个 \(b\),右侧的 \(a\) 一定是第一个 \(a\),所以我们再维护一下 \(p,s\) 表示每个线段树节点所维护的区间中首个/最后一个某字母出现的位置即可。这样直接合并是 \(\mathcal O(\Sigma^4)\) 的。
不过还可以优化。考虑到是否能够拼合只和左边的 \(b\)、右边的 \(a\) 有关,所以我们可以把东西看成三个矩阵相乘,就可以把合并优化到 \(\mathcal O(\Sigma^3)\) 了。
总时间复杂度 \(\mathcal O(q\Sigma^3\log n)\)。
序列交换
考虑这个问题本质上要求我们把所有数分成两类,一类丢到左边一类丢到右边。但是麻烦的是贡献很复杂,非常难算。
考虑钦定,把交换的贡献摁在其中较小的那个数上,那么每个数产生的贡献全部来自于和更大的数交换,我们就不需要再考虑它和较小的数交换产生的贡献了。此时我们再考虑一个数往两侧交换产生的贡献,很明显它恰好必须要经过左侧或右侧那些比它更大的数,而我们通过钦定让当且仅当这一部分才产生贡献,于是就能用 BIT 简单算出贡献,每次都选择较小的一边就做完了。
P11920 [PA 2025] 乘数 / Mnożenie cyfr
真的无法了。
首先我们要知道这种题怎么下手。我们需要观察到这个 \(f(x)\) 不在乎 \(x\) 的值是多少,只在乎 \(x\) 中数位构成的多重集。我们可以把每种多重集看成一个等价类,该等价类内的东西变化过程都是相同的,最终得到的结果也是相同的。
所以计数的思路应该是,我们一个等价类一起打包数到。容易发现后半截是简单的:给出多重集,我们可以用简单的数位 dp 来算出有多少种安排方案让它 \(\le n\)。
然后考虑能不能枚举等价类。不妨爆搜所有可能组成 \(10^{18}\) 以内数的多重集,为了枚举和数位 dp 方便(或者你也可以发现变出 \(0\) 的数量是最多的),我们不管包含 \(0\) 的多重集,因为这种多重集肯定会变成 \(0\),而最终变出 \(0\) 的答案我们可以补集转化出来。可以发现不会变成 \(0\) 的多重集只有 \(48367\) 个。
到这里直接做一个简单的数位 dp 就可以通过了。但我们能不能再塞塞?可以发现很多不同的多重集的 \(f\) 也是一样的,而 \(f\) 一样也意味着最终得到的结果相同,所以我们把 \(f\) 相同的也塞在一起。可以发现所有多重集产生的不同 \(f\) 只有 \(193\) 个!
所以现在我们考虑计数有多少个 \(n\) 以内的数 \(x\) 的 \(f(x)=y\)。这也是个非常简单的数位 dp,只需要求出 \(t\) 位数有多少种方案使其乘积为 \(y\),由于我们只需要询问 \(193\times 18\) 个状态,所以写记忆化搜索即可。
P11885 [RMI 2024] 跑酷 / Jump Civilization
显然限制等价于 \(i\to v_i\) 构成的东西要么包含要么不交。
考虑经典转化,我们把这种关系做成一棵树。考虑造一条 \(0\to n\) 的边来包裹最外层的 \(i\to v_i\),随后我们考虑如何在这棵树上刻画 \(i\to v_i\) 和 \(i\to i+1\)。
我们设位于该树上的一个点 \(i\) 意味着我们位于它对应那条边的起点。
- \(i\to v_i\):考虑起点为 \(v_i\) 的边在树上的哪里。考虑简洁的情况是 \(i\to v_i\) 和 \(v_i\to v_{v_i}\) 是同层的,此时我们只是到达了它的右兄弟。随即我们发现可以推广开,当找不到右兄弟时我们就往祖先回溯,直到存在右兄弟跳过去即可。
- \(i\to i+1\):起点为 \(i+1\) 的边显然是当前子树的最左儿子。
显然在树上的一条路径 \(i\to j\) 对应着原问题的 \(s_i\to s_j\),所以我们尝试就在这个树上刻画两点距离。显然它是简单的:它就是 \(i\) 到 \(\operatorname{LCA}\) 下面的右兄弟数量之和,加上 \(\operatorname{LCA}\) 下面到 \(j\) 的左兄弟(含自己)数量之和,特别地,\(\operatorname{LCA}\) 的下面那个地方只需考虑两侧中间的那些兄弟,所以恰好多算了 \(\operatorname{LCA}\) 的儿子数量步。
不妨设 \(a_i\) 表示根到 \(i\) 的节点右兄弟数量和,\(b_i\) 表示根到 \(i\) 节点的左兄弟数量和,\(c_i\) 表示根到 \(i\) 节点的儿子数量和,那么贡献恰好就是 \(a_i+b_j-c_{\operatorname{LCA}(i,j)}\)。
然后我们考虑对于每个点 \(i\) 怎么计算有多少个 \(j\ge i\) 使得 \(a_i+b_j-c_{\operatorname{LCA}(i,j)}\le k\)。对于 \(j\) 在 \(i\) 子树内的部分显然是求一个偏序,离线 BIT 即可(注意子树内的贡献不满足这个式子,有细节)。
对于 \(j\) 在 \(i\) 子树外的部分,我们考虑枚举 LCA,然后依旧 dsu。直接想似乎不太容易想清楚,我们考虑按照 \(i\) 是否在 LCA 重儿子内分类去看贡献来方便想清楚这个过程。
如果他在我们枚举的 LCA 的重儿子内,我们无法枚举这个点,但我们需要考虑所有轻儿子的贡献。这可以通过我们在 dsu 的过程中加入轻儿子贡献并递归重儿子来做到。
如果他在我们枚举的 LCA 的轻儿子内,我们可以枚举这个点。由于我们知道了 LCA 也知道了这个点,所以对它产生的贡献是只关于一个区间的点及其点权的偏序,可以用主席树来在线得到,也可以离线下来最后做一遍树状数组。
时间复杂度 \(\mathcal O(n\log^2n)\)。
CF2128E2 Submedians (Hard Version)
为啥想到了中位数连续也不会吧!
经过一段时间的思考之后我们发现,如果给出区间 \([l,r]\) 并在此基础上将区间向外扩展或向内收缩一格,新的中位数区间一定在 \([l,r]\) 的中位数区间的旁边。换句话说,可以取到的中位数一定是连续的。
那么我们考虑从中位数最小的区间移动到中位数最大的区间,不管移动方法是什么,这当中就一定能取到所有我们想要的中位数。为了让移动方式中总能够符合长度要求,我们用莫队的方法去移动:先扩展再收缩。
考虑我们怎么找到中位数最小和最大的区间。不妨以最大的为例,我们考虑二分,check 是否存在一个长度 \(\ge k\) 的区间中位数 \(\ge mid\)。trickily,我们把 \(\ge mid\) 的元素设置为 \(1\),其它的设置为 \(-1\),那么 check 区间和 \(\ge 0\) 就可以了。这可以帮助我们通过 Easy Version。
然后考虑怎么在区间移动时维护中位数,可以发现移动的同时在线段树上二分即可。
P13536 [IOI 2025] 神话三峰(triples)(Part 1)
做这题的时候提前获得了根号分治的 hint。遇到所有元素分成一组一组的情形一定要考虑对每组元素个数根号分治。
考虑 \(\max(H_i,H_j,H_k)\) 显然是唯一的,它就等于 \(k-i\)。不妨枚举最大值的位置。
当最大值位于 \(i,k\) 时,我们可以直接解出另一个位置,然后问题归于平凡。
当最大值位于 \(j\) 时,我们进一步讨论 \(H_i\) 和 \(H_k\) 的情况:
当 \(H_i=j-i,H_k=k-j\) 时,我们有 \(j=i+H_i=k-H_k\)。考虑到每个 \(j\) 我们只会枚举一次,所以我们可以枚举 \(i+H_i=j\) 的位置 \(i\),这显然是均摊的。得到 \(i\) 之后,根据 \(H_j=k-i\) 我们可以得到 \(k\),之后的问题是平凡的。
当 \(H_i=k-j,H_k=j-i\) 时,我们依然有 \(i+H_i=k-H_k=C\),但是 \(C\) 不再是 \(j\) 而是一个未知的常数。考虑到不同的 \(C\) 之间显然是独立的,我们可以尝试枚举 \(C\) 倒回来计算贡献。
对于存在 \(\le \sqrt{2n}\) 个 \(x\) 使得 \(x+H_x=C\) 或者 \(x-H_x=C\) 的 \(C\),根据经典结论我们知道我们可以直接在里面应用平方算法枚举 \(i,k\)。之后可以解出 \(j\),问题归于平凡。
对于大于根号的部分,显然这部分只有根号个 \(C\)。我们考虑对于每个 \(j\) 来枚举 \(C\),由于 \(k-H_i=j,i+H_i=C\),我们可以得到 \(k+i=j+C\),而 \(k-i=H_j\),所以也能解出 \(i,k\),问题归于平凡。
注意 \(H_i=H_k=k-j=j-i\) 会算重,我们钦定在第二部分算到即可。
CF1626F A Random Code Problem
费了点心思,幸好我的算法直觉还是不错的。
利用期望线性性,考虑枚举 \(1\le i\le n,1\le j\le k\) 表示第 \(j\) 次选到下标 \(i\),我们只需求出所有情况下这个位置上值的和,然后乘上 \(n^{k-1}\) 算进答案就可以了。
显然需要一个容斥,设 \(F_{i,j}\) 表示前 \(j\) 位所有情况下 \(a_i\) 扣掉的数之和,那么我们实际上只需计算:
注意到这个式子显然和 \(i\) 没有任何关系,所以我们考虑求出 \(F_j\) 表示在前 \(j\) 位所有情况下,所有数扣掉的数之和。
我们不妨计算 \(f_j\) 表示在前缀所有可能的情况下第 \(j\) 位这一位上扣掉的和,最终显然 \(F_j=\sum\limits_{p<j} f_pn^{j-p}\)。
为了计算 \(f_j\),我们显然需要计算一个数组 \(g_{j,p}\) 表示此时所有情况下有多少个数 \(\bmod j=p\)。考虑我们从 \(j\to j+1\) 转移数组 \(g\) 需要得知在 \(\bmod j=p\) 的数 \(\bmod (j+1)\) 的情况,这意味着我们不得不把所有数放在模 \(\operatorname{lcm}\{1,2,3,\ldots,k\}\) 剩余系下考虑,这个数恰好只比 \(10^7\) 多一点。
所以我们尝试维护一个 \(\operatorname{lcm}\) 大小的背包 \(h_p\) 表示所有情况下有多少个数 \(\bmod \operatorname{lcm}=p\)。这个我们就很好转移了,因为我们可以清楚地对每一个 \(j\) 知道 \(h_p\) 里面那些数现在 \(\bmod j\) 是多少。
时间复杂度 \(\mathcal O(k\operatorname{lcm}\{1,2,3,\ldots,k\})\)。在没有小样例的情况下想清楚比较恶心。
P7246 手势密码
大一统树上取链型贪心!!!
考虑这种贪心题有两个量比较重要,\(f_u\) 表示 \(u\) 子树内的链数量,\(g_u\) 表示 \(u\) 子树内还可以向上的链数量。我们容易发现在本题中,我们需要贪心地先最小化 \(f_u\),在此基础上最大化 \(g_u\)。因为较大的 \(f_u\) 虽然可能拥有更多 \(g_u\),但这没有意义,保留到上方去合成链不如在这里面合成。
考虑 \(f,g\) 的值显然与在点 \(u\) 上来自不同儿子的链的匹配数强相关。我们可以用众数定理轻易计算这个点上允许的最大匹配数,不妨记为 \(c\),之后我们设 \(0\le x\le c\) 表示匹配起来的链的数量,我们可以定量计算出 \(f_u,g_u\):
\(f_u\) 的式子中粉色的部分表示该节点上需要新增的链数,因为所有向上的链可以覆盖 \(\sum g\) 次,但是由于有合并,所以又要少覆盖 \(x\) 次。
获得这个式子之后显然要根据 \(\max(0,a_u-(\sum\limits_{v\in\operatorname{sons}_ u} g_v)+x)\) 的值分类讨论。
- 当 \(x\le (\sum\limits_{v\in\operatorname{sons}_ u} g_v)-a_u\) 时,该式子取到 \(0\)。此时由于 \(f_u\) 越小越好,所以我们希望 \(x\) 越大越好。那么显然 \(x\) 会取两个限制中的较小值。
- 当 \(x\ge (\sum\limits_{v\in\operatorname{sons}_ u} g_v)-a_u\),该式子取到 \(a_u-(\sum\limits_{v\in\operatorname{sons}_ u} g_v)+x\)。此时 \(f_u\) 直接就是个定值。由于 \(g_u\) 越大越好,所以我们希望 \(x\) 越小越好。那么显然 \(x\) 会取两个限制中的较大值。
然后把两种情况再取一次较优的即可。
P4647 [IOI 2007] sails 船帆
首先策略是比较好想的。我们考虑最终答案和每一层上船帆数量的平方和有关,我们希望安排每一根船帆在长度为 \(h_i\) 的前缀中放置 \(k_i\) 个 \(+1\) 的方法来最小化这个平方和。
我们考虑把所有船帆按照高度 \(h_i\) 从小到大排序,先处理比较松的限制再处理比较紧的。
对于每一根船帆,我们显然选择当前最小的 \(k_i\) 个放置 \(+1\)。
于是我们轻易获得了一个 \(\mathcal O(n^2\log n)\) 的算法,可以获得 \(51\) 分。
考虑优化。我们本质上就是维护一个序列,每次将最小的 \(k_i\) 个 \(+1\),并支持往序列中加 \(0\)。考虑我们维护该序列的单调不增性,那么可以发现,我们加最小的实际上可以分成两段:设第 \(k_i\) 小的数为 \(v\),那么实际上是所有 \([1,v)\) 中的数直接 \(+1\),而 \(=v\) 的数排在一起,我们加它的一个前缀。显然这样序列还是单调不增的。
至于加 \(0\),我们直接往后扩展序列即可,因为在尾部加 \(0\) 同样不影响序列的单调不增性。
线段树或树状数组上二分即可。
CF578E Walking!
显然这个题是要把 \(s\) 划分成尽量少的 L 和 R 交替的子序列,并且最后要把所有子序列拼起来。
前者存在一个显然的贪心:能放进去就放进去,不行就新开一个子序列。
最后你发现问题其实在于接不起来!我们发现,如果只存在 L...R 和 R...L 型子序列,那么我们就接不起来了。但是如果我们存在 R...R 或者 L...L 型子序列,考虑到 L...R 和 L...R 之间可以自己接自己,就一定能接起来。
那么我们考虑只存在 L...R 和 R...L 怎么办。不妨考虑调整——我们取出两个序列,可以发现总是可以把其中一个的末尾放到另一个后面,这样就调整成一个 L...L 和一个 R...R 了。
CF623D Birthday
有点神秘。首先这个贡献我就不是很会算……
先考虑假设我们获得了策略怎么计算期望。对于第 \(k\) 轮,我们试图计算出 \(f_k\) 表示游戏在第 \(k\) 轮之后结束的概率。显然这和前 \(k\) 轮中我们猜测每个人的次数 \(c_i\) 有关系,因为我们要求在 \(c_i\) 次猜测中猜到这个人,所以概率实际上是:
因为有可能在第 \(k\) 轮之前就猜完了,所以要容斥一下。
那么我们希望最小化 \(\sum f_kk\)。
首先显然前 \(n\) 轮我们需要把所有人猜一遍。
之后考虑到每一步都是一个独立的不增加信息量的决策,我们合理猜测贪心是对的:选择一个能让下一轮的 \(f\) 最大化的人。
Proof.
首先我们的方针肯定是没问题的,因为所有轮结束的概率之和肯定是 \(1\),我们尽量最大化较小轮次的终止概率肯定是优的。
之后考虑找到第一个按照贪心算法 \(f\) 没能最大化的位置。这意味着存在另一种选人使得 \(\prod\limits_{i=1}^n 1-(1-p_i)^{c_i}\) 更大。然而事实上可以用调整法证明不存在这种情况。
考虑到精度误差要求是 \(10^{-6}\),实际上我们只取策略的前 \(3\times 10^5\) 轮就足够逼近答案了。
P8352 [SDOI/SXOI2022] 小 N 的独立集
显然是 dp 套 dp,但是我们发现问题在于最大权独立集的 dp 在根不选的时候要传 \(\max(f_{v,0},f_{v,1})\),但我们不能接受在状态记录两个值。
注意到 \(f_{u,0}+a_u\ge f_{u,1}\)。因为 \(f_{u,0}\) 的儿子选法实际上显然是 \(f_{u,1}\) 的超集,所以如果把 \(f_{u,1}\) 唯一的优势 \(a_u\) 给到 \(f_{u,0}\) 那么它也不差的。
我们考虑用这个东西来优化状态。考虑对于 \(f_{u,0}\) 来说,同时有小于等于它的 \(f_{u,1}\) 的状态显然是可以压在一起的(这种情况下大家都会用 \(f_{u,0}\),所以 \(f_{u,1}\) 的具体值无关紧要),所以我们只需要记录 \(k+1\) 种 \(f_{u,1}\) 的值。对于 \(f_{u,1}\) 来说,大于等于它的 \(f_{u,0}\) 显然是没有必要记录的(这种情况下没有状态会使用 \(f_{u,1}\) 转移,所以直接抛弃),所以我们只需要记录 \(k\) 种 \(f_{u,0}\) 的值。把这两种状态都用差值来记录状态即可。
用树形背包的办法来转移,时间复杂度 \(\mathcal O(k^4n^2)\),需要卡常。
P5883 [CTSC2013] 没头脑和不高兴
组合意义太厉害了。
显然答案是逆序对的数量,我们考虑求出每对 \(i<j\) 成为逆序对的概率,最后再求和。
设需要排序的点集为 \(S\),我们有:
- \(i,j\) 均在排序集合,显然为 \(0\)。
- \(i,j\) 均不在排序集合,显然为 \(\frac{1}{2}\)。
- \(i\) 在排序集合。假设我们有 \(t\) 个点需要排序,那么我们实际上是想求有多大的概率能在剩下的 \(n-t\) 个数里面取到一个 \(a_j\) 比这里还小的。考虑这样一个映射:我们不妨在所有数中任取 \(t+1\) 个数,把原问题变成从中选择一个抠掉为 \(a_j\),剩下的依次为排序集合的过程。然后设 \(i\) 在排序集合中位于从小到大第 \(p_i\),那么我们必须在 \(t+1\) 个数中把不在排序集合的点 \(j\) 放在前 \(p_i\) 个的位置之一。可以发现,这样做每一对可能的 \((a_i,a_j)\) 产生的次数依旧是相等的。所以这个问题的概率和原问题的概率一致,为 \(\frac{p_i}{t+1}\)。
- \(j\) 在排序集合是类似的,只不过我们要找一个比它大的,概率为 \(\frac{t+1-p_j}{t+1}\)。
现在让我们来考虑维护期望。
假设排序集合为 \(S\),那么前两类产生的贡献和是简单的:
用线段树维护有多少点在排序集合里面,支持区间推平即可。
然后考虑后两类贡献。不妨以第三类为例:
我们充分发扬人类智慧,利用 \(p_i=\sum\limits_{j=1}^{p_i} 1\) 把贡献拆开,换句话说,每个在排序集合内的数把自己的概率平摊到自己及前面,这样每个都贡献 \(\frac{1}{|S|+1}\)。可以发现我们实际上是想数三元组 \(k\le i<j\) 使得 \(a_k=a_i=1,a_j=0\) 的数量。这个就是纯粹的半群信息,可以用线段树简单维护了。
反过来的第四类也是同理的,我们只需要数三元组 \(j<i\le k\) 使得 \(a_k=a_i=1,a_j=0\) 的数量即可。
这样可以得 \(50\) 分。现在还剩下一个问题:初始情况下的方差。
不妨设逆序对数量为 \(I\),众所周知,方差 \(V=E(I^2)-E(I)^2\),现在我们显然可以简单算出 \(E(I)\),考虑怎么算出初始序列逆序对数量的平方的期望。
有一个办法是强行管道取猪,但这个问题非常 hard,因为四个点的可能性有 \(2^4=16\) 种(虽然有些情况是可以合并的),我们需要使用巨量分类讨论。
注意到初始序列的答案只和 \(n\) 有关,这提示我们答案很有可能就是一个式子算完,毕竟我们显然可以用一个式子把 \(E(I)^2\) 搞出来,\(E(I^2)\) 应该也差不到哪去。容易猜到这个式子次数应该不是很高,并且应该要分奇偶,于是我们直接搜到 \(n=10\),把答案的多项式插出来就完了!!
T2. 白云(cloud)
对于 phi 的问题而言,拆成质数乘积是很有效的。
显然那个式子是 \(n-\varphi(n)\),我们需要让它等于 \(m\)。我们不妨考虑构造 \(n=pq\) 其中 \(p,q\) 为不相同的质数,这样 \(\varphi(n)=(p-1)(q-1)=pq-p-q+1\),那么 \(m=p+q-1\iff m+1=p+q\)。
由哥德巴赫猜想,任何一个大于等于 \(4\) 的偶数都可以拆成两质数之和。对于大部分情况,我们可以直接枚举 \(p\),考察 \(m+1-p\) 是否是质数即可,可行的分解会在很小的时候就出现。在比较小的情况我们会出现只能 \(m+1=2p\) 的情况,需要特判。
T4. 停留(stay)
逆天双射来的。
考虑 \(x=y\) 是简单的,此时所有 \(\bmod x\) 剩余系的链都独立。
接下来我们考虑类似的独立性质在一般情况怎么表达。我们知道任意两个点 \(a,b\) 可达至少 \(a-b\) 要满足裴蜀定理,所以所有 \(\bmod \gcd(x,y)\) 剩余系的点显然是独立的。
之后对每一个剩余系,我们显然可以 \(x\gets \frac{x}{\gcd(x,y)},y\gets \frac{y}{\gcd(x,y)}\),这相当于对每个独立的部分重编号所有点,把内部相邻点间 \(\gcd(x,y)\) 长度的间隔压缩掉。这样可以使得 \(\gcd(x,y)=1\)。
然后我们考虑怎么在 \(\gcd(x,y)=1\) 的情况下刻画两种边。这种二元的东西一定要考虑放到平面上刻画。我们不妨把所有点 \(i\) 映射到一个 \(\left\lceil\frac{n}{y}\right\rceil\times y\) 大小的网格图上,每个原来的点 \(i\) 对应到点 \((\left\lceil\frac{i}{y}\right\rceil,(i\cdot x^{-1})\bmod y)\),于是我们发现,连向 \(+y\) 的点是从上一行向下一行同一列连边;连向 \(+x\) 的点是从上一列向下一列循环移位地连边,但不一定是同一行,也可能是向下一行(钦定 \(x<y\))。
这个网格图中虽然有多余的点,但是显然多余的点不影响我们数匹配。
考虑在网格图上数匹配。一个显然的办法是我们把一行点在匹配中的情况状压在一起,然后使用轮廓线 dp,复杂度 \(\mathcal O(n2^{y})\)。
显然我们也可以沿着列压。但是沿着列压需要我们记录第一列点在匹配中的情况来考虑最后一列点,仍然使用轮廓线 dp,我们的状态数是 \(\mathcal O(2^{\frac{2n}{y}})\),时间复杂度 \(\mathcal O(2^{\frac{2n}{y}})\)。
显然取根号平衡,按照 \(y\le \sqrt{2n}\) 根号分治,时间复杂度为 \(\mathcal O(n2^{\sqrt{2n}})\),可以通过。
但是这个太难写了!细节多到根本不是人类能在赛场上写出来的!所以我们还有另一个很智慧的做法:
考虑直接对着原图做,我们假设所有 \((i,i+x)\) 和 \((i,i+y)\) 的边都存在,那么我们直接从每个连通块最左边的点开始 BFS,感性理解地,两个有边的点应该不会相距太远。
Proof.
延续前一个做法的理解,对于同一连通块,两个点在 BFS 序上中间的距离最多只有行上那些点或者列上那些点,所以差不多是 \(\mathcal O(\sqrt{2n})\) 个。为啥是差不多呢?因为本题最大距离要设置到 \(25\) 才能通过。
有了这个做法事情就简单多了。我们直接在 BFS 序的序列上跑 \(x,y\le 15\) 那个状压 dp:维护向前 \(25\) 个点每个的被选择情况即可。
时间复杂度大概也是 \(\mathcal O(n2^{\sqrt{2n}})\),这个实在好写了很多。
【模拟赛 10.6 #D】量筒注水(cylinder)
哎,神秘流水题。
图上题看着就很神秘,我们考虑有没有什么性质。由于与第一个量筒连通的水面遵循连通器原理,我们可以发现水面上升流过水管使得某些水管被水充满的过程类似 Kruskal。据此我们发现本题中我们只需保留最小生成树,因为当有水流过不在最小生成树上的水管时,两个量筒中一定已经因为连通器原理有与这根水管等高的水了,所以这根水管没有意义。
于是问题来到树上。
这种问题很有必要确定水平面的高度信息。我们不妨二分 \(p\) 中水的深度为 \(mid\),那么我们可以发现,从它开始只经过高度 \(<mid\) 的水管能到达的量筒连通块中水的高度均为 \(mid\)。因为这个连通块向外的水管都高于 \(mid\) 所以和外界独立,而内部需要遵循连通器原理。
我们考虑使得这个连通块 \(S\) 充满高度 \(mid\) 的水的过程。考虑找到连通块中距离量筒 \(1\) 最近,或者说深度最小的点 \(t\),那么显然我们会先让水流入这个点。
Lemma. 当水流入点 \(t\) 时,之后在 \(t\) 的水面到达 \(mid\) 之前,水都只会源源不断地流入 \(t\)。
Proof.
假设 \(t\) 与量筒 \(1\) 连通块之间的水管高度为 \(H\)。那么当水开始流入 \(t\) 时,量筒 \(1\) 连通块已经有了稳定的高度为 \(H\) 的水面——这个连通块中没有任何可以除了 \(t\) 以外的向外流的缺口。假设存在一个这样的缺口,那么这个缺口的水管高度一定小于 \(H\)(所有水管高度不同),那么水面就不可能来到 \(H\) 的高度。
据此,从现在开始,水都会源源不断流入 \(t\),直到我们这个连通块都被填充上 \(mid\) 高度的水(因为 \(mid\le H\) 所以在 \(mid\) 高度及以前都不会影响量筒 \(1\) 连通块把水往 \(S\) 中送的行为)。假设使得 \(t\) 中有水至少需要 \(f_t\) 高度的水注入量筒 \(1\),那么我们需要的水量就是 \(f_t+|S|\cdot mid\)。
连通块 \(S\) 的大小和 \(t\) 可以在大根 Kruskal 重构树上倍增求出。
接下来考虑怎么预处理出所有 \(f_t\)。可以发现这个操作是类似的,假设 \(t\) 和 \(fa_t\) 之间的水管高度为 \(H\),我们等价于要让 \(fa_t\) 有稳定的高度为 \(H\) 的水面,这样接下来 \(\epsilon\) 的水就会直接流进 \(t\)。可以发现这个等价于在 \(fa_t\) 上做二分的 check(H),所以我们类似判定的办法用 Kruskal 重构树找出连通块的最浅点 \(t'\) 和集合大小 \(|S'|\),显然 \(t'\) 在原树上是 \(t\) 的祖先,所以我们从上到下递推 \(f_t=f_{t'}+|S'|\cdot H\) 即可。
P5982 [PA 2019] Trzy kule
不会啊,真的不会。我咋这么菜啊。
考虑我们可以把某个位置上三个字符串的状态 \(S\) 和 \(\overline{S}\) 合并在一起:我们不去生成原串,而去生成它的双射“在这些位置上是否和 \(S_1\) 不同”的 \(\texttt{01}\) 串。这样三个字符串的状态只剩下 \((0,0,0),(0,0,1),(0,1,0),(0,1,1)\)(\(0\) 表示该字符串该位置和 \(S_1\) 相同,\(1\) 表示和 \(S_1\) 不同)。不妨设四种状态的总数为 \(c_{000},c_{001},c_{010},c_{011}\),枚举 \(i,j,p,q\) 表示每种状态内有多少个和 \(S_1\) 不同,那么我们本质上是要求满足:
的所有 \(i,j,p,q\) 四个组合数系数之和。
系数显然是独立的,所以我们可以尝试 mitm 拆限制。我们先枚举 \((i,j)\),然后考虑式子对 \(p,q\) 的限制形如 \(p+q\) 和 \(p-q\) 都在一个区间里,也就是一个矩形上的所有 \(p,q\) 的贡献和。那么我们直接预处理所有 \(p,q\) 的系数,放在 \(w_{p+q,p-q}\) 上,矩阵 \(w\) 的大小显然是 \(n\times n\),二维前缀和即可。
时间复杂度 \(\mathcal O(n^2)\)。
P7386 「EZEC-6」0-1 Trie
首先经过观察可以发现递推式:
答案就是 \(f_{n,m}\)。
然后我们考虑类似组合数的递推,思考这个东西的组合意义来得到它的通项。
考虑 \(f_{n,m}\) 必然可以表示为关于 \(\sum C_jf_{1,j}+2C_0\)。我们尝试计算这个系数。
\(C_j\) 显然是简单的,我们考虑递推系数:
考虑这个东西的组合意义显然是只能往右下或者右侧走的路径数,从 \((2,j+1)\) (因为第一步必须往右下)走到 \((n,m)\)。考虑往右的总步数 \(m-j-1\),从中选出往下的 \(n-2\) 步即可,所以方案数是 \({m-j-1\choose n-2}\)。
然后考虑怎么算 \(C_0\)。可以发现任意一个 \(2\le i\le n,1\le j\le m\) 都在系数中新产生一个 \(2\),之后的贡献系数显然是 \((i,j)\) 到 \((n,m)\) 的路径数量。于是:
对 \(C_0\) 使用上指标求和吧!我们有:
然后现在让我们回到前面 \(C_j\) 的部分。这部分的式子是:
考虑转换贡献形式。每个 \({m-j\choose n-2}\) 要贡献 \(j\) 次,那么我们把它平摊到 \([1,j]\) 上,那么式子变为:
依旧上指标求和两次:
所以最终的式子是:
Lucas 算它即可。
T4 高中生数学题
显然考虑建图,那么问题转化为给点分配点权,要求相邻点的点权积之和最大。设一个点邻域所有点的点权和为 \(s_u\),我们可以把答案写成 \(\frac{1}{2}\sum\limits_{u=1}^n\sum\limits_{v\in N(u)} a_ua_v=\frac{1}{2}\sum\limits_{u=1}^na_us_u\)。
考虑这个题最麻烦的点在于那个上下界。考虑观察性质,可以发现,如果有两个点 \(u,v\) 没有碰到上下界,但是它们两个不相邻,那么我们总是可以把 \(s\) 较大的那一方增大,\(s\) 较小的那一方减小,这样显然答案会变大。直到有一方达到界。
于是我们可以认为,最终答案中所有没有碰到上下界的点构成一个完全图 \(K\),因为它们必须两两相邻。我们直接在原图里钦定出来这个完全图,然后剩下的点就只有上下界两种可能了。我们干脆这样钦定:\(3^n\) 枚举所有点的状态是上界/下界/中间,再判断中间那部分是否构成完全图。
现在我们考虑怎么给那些没碰到上下界的点赋值。这实际上也是那个 \(20\) 分的部分分。
设 \(K\) 中所有点的点权和为 \(M'\),每个点邻域中不在 \(K\) 中的点的点权和为 \(a_u\),那么我们实际上希望得到一组 \(\sum x_u=M'\) 使得:
最大化。
化简,我们实际上希望最大化:
扔一个常数进去,于是我们实际上希望最小化:
显然我们取 \(x_u=a_u\),然而这样不一定让 \(\sum x_u=M'\),我们要朝 \(M'\) 的方向填补一下。根据经典贪心,对于每个 \(\epsilon\),我们一定把它放在最小的数上,循环往复,最终每个 \(x\) 都是相等的。所以 \(x_u=a_u+\frac{M'-\sum a_u}{|K|}\)。
最终我们 check 一下 \(x\) 是否满足钦定即可。
通过精细实现,时间复杂度 \(\mathcal O(n3^n)\)。卡常得不行我加了火车头才过。
CF1667E Centroid Probabilities
考虑这种树我们肯定希望以 \(1\) 为根,这样从上往下点是递增的。我们考虑怎么在确定根的树上简单地找到重心。
设 \(m=\frac{n+1}{2}\) 有一个判定是最深的那个子树大小 \(\ge m\) 的点就是重心。这个看起来就很好数。
我们先考虑 \(f_i\) 表示以 \(i\) 为根的子树的大小 \(\ge m\) 的树的方案数。不妨枚举子树大小:
在剩下的 \(n-i\) 个点中选 \(j-1\) 个点塞进来,内部在内部任意地选择比自己小的父亲,外部也在外部任意地选择比自己小的父亲,最后 \(i\) 自己还要选一个父亲。
然后考虑怎么扣掉里面还有 \(\ge m\) 的子树的方案数来得到答案 \(g_i\)。显然考虑容斥。考虑到它下面可能有一条链的子树大小 \(\ge m\),而我们显然不能斥多次,所以我们钦定一个不合法情况在它那个子树大小 \(\ge m\) 的儿子处被扣除,所以:
现在我们考虑快速计算 \(f\)。显然打开组合数:
P4831 Scarlet loves WenHuaKe
我居然会做,有点帅。
我们现在相当于每个列可以放两个炮。那么我们先考虑一个基础思想:我们把列摊开成 \(2m\) 个格子排成一行,把 \(2n\) 个炮按顺序填充进去。这样每个方案首先会算重 \(2^n\) 次,因为每一行的炮实际上是相同的,交换两个在同一行的炮构成一个完全相同的方案;其次会算重 \(2^c\) 次,其中 \(c\) 表示实际用到的列数,因为每个列的两个格子也是没有顺序区分的,交换用到的列上两个格子上的炮也构成一个完全相同的方案。
先考虑 \(n=m\),此时实际用到的列数就是 \(m\)。我们发现想要求出合法的把 \(2n\) 个炮按顺序填进去的方案还要做一个容斥:因为有可能同一行的两个炮放在表示同一列的两个格子里,而这显然是不被允许的。所以我们钦定一下这种东西的数量然后斥掉。
对于 \(n<m\),我们需要考虑实际列数的问题。我们对 \([n,m]\) 中所有的列数做上面那个东西,实际上是求出了至多使用 \(i\) 列的方案数,于是显然可以容斥出恰好用到 \(i\) 个列的方案数。这样我们就可以去重了,算出实际方案数之后再把 \(m\) 列补齐即可。
P9823 [ICPC 2020 Shanghai R] The Journey of Geor Autumn
感觉大脑褶皱被抚平了。
看完题显然的:前 \(k\) 个元素可以想怎样就怎样,但是 \(1\) 必须放在前 \(k\) 个里面。
我们不妨枚举 \(1\) 的位置 \(i\)。然后我们发现,\(1\) 后面的 \(k\) 个元素又因为 \(1\) 的存在可以想填什么就填什么了……所以实际上递归到了子问题 \(n-i\)。然后答案就是一个递推乘排列数,前缀和优化即可。
CF1765C Card Guessing
简单题。
首先期望线性性,我们计算每个位置上有多少种方案使得猜对。那么我们容易写出一个 \(\mathcal O(n^5)\) 的算法:枚举位置,枚举前面那些决策的位置每种牌出现了多少次,然后我们钦定第一种枚举的牌是猜测的那种(也是最少的那种),然后一堆组合数乘起来算出猜对的牌堆方案数,根据剩下几种牌是否和第一种牌出现次数相同计算猜到第一种的概率,最后再乘 \(4\) 取消钦定即可。
然后考虑优化。显然我们可以 mitm,就和这个题完全一样操作即可,把最后两种独立出去。注意处理一下和第一种牌相同的 case。
时间复杂度 \(\mathcal O(n^3)\)。
QOJ833. Cells Blocking
被 trick 打烂了!
你做过一个题叫 [NEERC2012] Labyrinth of the Minotaur,在这个题中我把 \((1,1)\) 到 \((n,m)\) 的四连通性转化成右上边框和左下边框的八连通性来处理。
但是这个题还有另外一个更为清新的做法!我们贪心地考虑,如果我们能找出一条尽量向左的路径(“左手路径”)和一条尽量向右的路径(“右手路径”),那么所有的路径都被包在这两条路径之间。放置一个正方形障碍使得 \((1,1)\) 和 \((n,m)\) 不连通的必要条件是 ban 掉这两条路径,但因为正方形是连续的,所以这显然也 ban 掉了这两条路径之间的所有路径,于是这是必要的。
我们用这种方法来刻画使之不连通的问题非常有效。
回到这个题,这个题我们虽然只能向下和向右走,同样可以刻画出左手路径和右手路径。
随后容易发现,如果我们选择放一块来 ban 掉两条路径交上的点,就直接没有路径了。此时就可以随便放置另一块。
如果我们放一块没有放到交上,显然两块必须各自在左手路径和右手路径上。我们考虑 \(\mathcal O(n+m)\) 地枚举其中一块在右手路径上的位置,然后考虑左手路径上有哪些点占用之后所有路径都没了。显然是新的右手路径和左手路径的交上那些。我们考虑怎么求出新的右手路径。
有一个聪明的办法是:我们从这个点往右上角走,新的右手路径显然一定经过它右上角的一个点,并且可以保证不经过它本身。而第一个可以找到从前来和从后来两条路径的点就是新的右手路径经过的点,因为再往右上的点都更靠左。找到这个点然后重新贪心构造出来即可。
时间复杂度 \(\mathcal O((n+m)^2)\)。听说有 \(\mathcal O(nm)\) 的做法。
CF720D Slalom
我们先改成比较熟悉的向下向右。
很容易发现,这个数数实际上是在说对于每一列上矩形裂出的间隔,只要两条路径经过的间隔序列是不同的那么就是不同的路径,否则就是相同的。这是很好理解的,经过哪个间隔就代表了一种在矩形上方或下方的位置信息。
维护 \(f_{i,j}\) 表示对于第 \(i\) 列的每个间隔 \(j\),到达它的路径的方案数,那么我们从 \(f_{i-1}\) 中和它相交的间隔求和转移过来。
然而维护间隔需要非常复杂的珂朵莉树,这很难写。这题只能向下或向右移动,所以我们可以把每个间隔摁到它的顶部计数,换句话说,对于所有本质相同的路径,我们在它的代表元——尽可能靠上的那条路径数到。
那么 \(f_{i,j}\) 表示第 \(i\) 列第 \(j\) 行,到达它的尽量靠上的路径的方案数。
那么转移实际上是:
- 对于一般的 \((i,j)\) 为空的位置,\(f_{i,j}\gets f_{i-1,j}\)。
- 考虑第 \(i\) 列新增的矩形,假设我们希望这条路径来到那个矩形之下,那么设矩形下边框为 \(k\) 最小的 \(j\) 使得 \(j\to k\) 没有遮挡,我们转移 \(\sum\limits_{p=j}^k f_{i-1,k}\) 给 \(f_{i,k}\),表示把这个矩形分到上面。
线段树维护即可。不知道为什么这个东西我都想不清楚。
CF1716F Bags with Balls
Stirling 有意思吗???
回顾第二类 Stirling 数的定义,\(\begin{Bmatrix}n\\ k\end{Bmatrix}\) 表示把 \(n\) 个有标号小球放进 \(k\) 个非空无标号盒子的方案数。我们容易用二项式反演来刻画它和普通幂的关系:
然后我们回到这个题。考虑写出式子:
用 Stirling 打开 \(F^k\),交换求和顺序之后构造一个组合数,然后显然用二项式定理:
\(\mathcal O(k^2)\) 预处理第二类 Stirling 数,剩下三项边枚举边算即可。
【模拟赛10.19 D】基础数据结构
这太难了。
我们显然需要枚举 \(j\)。考虑对于每个颜色,找出 \(j\) 及其左边第一个出现的位置 \(x\),\(j+1\) 及其右边第一个出现的位置 \(y\)。那么实际上 \(i,k\) 需要对所有颜色满足:
或者
也就是要么把这种颜色在两边都选上,要么都不要选上。
现在我们考虑再枚举一下 \(k\),来计数合法的 \(i\) 的数量。我们把所有 \((x,y)\) 按照 \(x\) 排序,那么对于一个合法的 \(i\) 来说,它前面的 \(x\) 需要满足对应的 \(y>k\),它及其后面的 \(x\) 需要满足对应的 \(y\le k\)。
所以我们考虑对于每个 \(k\) 找到一个分界线,也就是某个前缀 \(y>k\),它后面的后缀都满足 \(y\le k\),对答案的贡献就是这里相邻两项 \(x\) 的差。需要注意有可能所有的 \(y\le k\) 都取到,也即使得 \(y>k\) 的前缀是空前缀,此时相当于所有颜色都在我们的 \([i,j]\) 和 \((j,k]\) 中出现过,所以我们需要插入一个哨兵 \((0,n+1)\) 来合并这种情况。与此同时,显然不可能出现空后缀合法的情况。
然后我们考虑对于每个 \(k\) 维护有多少个断点使得它满足 \(y>k\) 而它的后继满足 \(y\le k\),产生贡献当且仅当有恰好一个断点满足条件,贡献就是这个点和它的后继的 \(x\) 差值。
由于我们要操作 \(j\),所以我们先把 \(k\) 这一维丢到一个线段树上,考虑维护每个 \(k\) 的断点数量和断点位置的差值。考虑到整个序列中至少有一个最靠前的点为 \((0,n+1)\),而存在至少一个点满足 \(y\le k\),那么我们一定可以找到至少一个断点。于是产生贡献的情况可以转化为断点数量取到最小值的情况。所以我们在线段树上记录区间的断点数量最小值,断点数量取到最小值的那些位置的断点 \(x\) 差值之和即可。
现在考虑操作 \(j\),可以发现 \(j\) 每次向后移动时,恰好是删一个点对又新增一个点对。我们用一个 set 维护所有点对按照 \(x\) 排序的结果,那么容易发现这种单点插入或删除对断点信息的影响只有它和它两侧的点产生的影响。这是一个区间断点数量加减,不影响我们的线段树信息维护。但我们还需要多维护一个区间断点数量取到最小值的位置数量,因为我们还要维护差值之和,而这个操作显然会导致某个区间的差值发生区间加减。
#P163. buy
难难的。
考虑把商品放到 \((a_i,b_i)\) 上,我们本质上是要把所有点划分到两个集合里,使得 A 集合的横坐标第奇数大,B 集合的纵坐标第奇数大之和最小,因为在买一送一的加持下我们只需也必须购买所有奇数大的点。
显然这种题的思路是要找出某种贪心的性质来来优化划分。考虑如果存在 \(a_i>a_j\),那么显然如果 \(b_i<b_j\),我们不可能在 A 商店买 \(i\),在 B 商店买 \(j\),分类讨论可以证明它至少不优于换过来,感性上也挺对的。
我们回到平面上说明这个性质。可以发现,如果 \((a_i,b_i)\) 表示一个位于 \(a_i\) 行 \(b_i\) 列的点的话,上述性质表达了如果 \(i\) 点被划分在 A 当中,那么它右上角的所有点都在 A 当中。于是最后划分到 A 当中的点会构成一个阶梯形状,存在一条从左上到右下的折线,使得折线及其上方的点在 A 中,折线下方的点在 B 中。
注意到折线实际上只有 \(\mathcal O(n)\) 个折点,因为这些点一定都是一个实际存在的点,否则可以调整。所有点的贡献可以在折线行动的同时计算,具体来说我们从右下往左上考虑折线,折线向上的时候算 A 集合贡献,向左的时候算 B 集合贡献即可。
据此我们可以写出一个简单的 \(\mathcal O(n^2)\) dp 来 dp 折线上的折点,钦定这些折点在 A 当中,而在它们之间的由于不知道折线怎么折而有可能在 A 有可能在 B 的点全部钦定到 B 当中即可。
现在考虑优化这个 dp。我们考虑每个点转移过来的贡献系数,实际上是中间这些行后缀中 \(a_i\) 的和和中间这些列后缀中 \(b_i\) 的和。所以我们可以从下往上扫描线,一边 dp 一边动态维护所有的转移贡献,线段树把一行拍扁,优化 dp 即可。
P6534 [COCI 2015/2016 #1] UZASTOPNI
我们考虑条件等价于子树选一个包含根的连通块,要求这个连通块恰好包含一个区间的权值的点。那么我们存在一个简单的 dp 是 \(f_{i,l,r}\) 表示根为 \(i\),包含 \([l,r]\) 的连通块是否可行。使用 bitset 来开第三维就开下了。
考虑转移这个 dp。我们可以预先把儿子按照儿子的权值全部排序(把根也当成一个儿子),这样我们永远只会往当前区间的后面添加,比较方便。考虑转移时需要枚举当前已有区间的左端点 \(l\) 和右端点 \(j\),之后相当于 \(f_{u,l,r}\gets f_{u,l,j}\& f_{v,j+1,r}\),本质上是一个按位或,bitset 可以方便地维护。
看上去复杂度是 \(\mathcal O(\frac{nv^3}{w})\) 的,但实际上不是的。考虑第二维的大小本质上只有 \(\mathcal O(siz)\),所以实际上我们在 \(\mathcal O(v)\) 枚举左端点之后,两边的右端点分别只需枚举到子树大小。显然这里构成一个树形背包复杂度证明,所以直接写的复杂度是 \(\mathcal O(nv^2)\) 的。如果手写 bitset,在每个点上只做子树大小范围内的 bitset 来保证复杂度,那么我们可以做到 \(\mathcal O(\frac{nv^2}{w})\)。
比较重要的是,本题实际上还有 \(\mathcal O(nv)\) 的解法。
考虑实际上我们的状态是设计得很差的,因为 \(v_i\in[l,r]\) 这一客观事实导致了大量的状态冗余,而显然如果我们在 \(v_i\) 处切开两侧一定是独立的。于是我们不妨设 \(f_{i,j}\) 表示 \(i\) 子树内能否凑出 \([j,v_i]\),\(g_{i,j}\) 表示 \(i\) 子树内是否能凑出 \([v_i,j]\)。向上合并转移时我们首先可以确定该儿子子树放在哪一边,注意同一侧的需要按儿子的权值排序,然后就很简单了,先转移靠近 \(v_i\) 的那个数组,再转移远离 \(v_i\) 的那个数组,合并出完整的贡献即可。这里的两维枚举直接就是 \(\mathcal O(nv)\) 的。
该做法也可以使用 bitset 优化。做到复杂度 \(\mathcal O(\frac{nv}{w})\)。
P13266 [GCJ 2014 Finals] Symmetric Trees
考虑观察性质,容易证明,树的重心一定在对称轴上,或者如果对称轴是一条边的话就在边的两端。因为考虑如果重心被分到某一侧,那么它只有至多一个子树的大小被分给了另一侧,而这个子树的大小严格不超过其他子树的和,于是得证。
找出对称轴上的一个点之后就随便树哈希结合递归判断了。
P12996 [GCJ 2022 #2] I, O Bot
真的会让人觉得是神秘贪心题的吧……
显然两侧独立,拆开做两遍一样的算法。
考虑一个显然的 dp,\(f_{i,j}\) 表示前 \(i\) 个里面选走了 \(j\) 个 O(此时显然选走了 \(i-j\) 个 I)的最小代价。这样每次向后,要么把这个点单独选了,要么从前面找一个没选的。可以发现,如果要找没选的显然找现在离原点最远的那个,容易证明如果留给后面的做相交的匹配是不优的。
考虑这个肯定过不了,然而也没有办法优化。我们直接强行塞在一起,\(f_i\) 表示前 \(i\) 个选完的最小代价!
那么显然有两条转移从 \(f_{i-1}\) 和 \(f_{i-2}\) 来,在此略过。
考虑还剩下什么可能的转移形式。不妨假设 \(i\) 处是 I,反过来同理。经过分类讨论容易得知我们从 \(j\le i-2\) 的地方拆一个 I 出来没有任何意义(利用 \(i-1\) 调整,之后仍然至多有一个 I 和 I 之间的匹配,产生贡献的匹配右端也是不劣的,所以整个都是不劣的,没有必要这样做)。所以只剩下从前面找到一个 O 匹配过来的情况。
依然考虑距离这里最近的那个 O,假设在位置 \(j\)。考虑中间的那些 I,可以发现以下几种情况可以调整成上述两种从 \(f_{i-1}\) 和 \(f_{i-2}\) 的转移:
- 有
I占据了这个 \(j\) 处的O。把那个I换出来,显然是不劣的。 - 有一个
I和另一个I匹配。如果这两个I都在中间,显然用 \(j\) 处的O和 \(i\) 处的I把它拆开不劣。否则这个匹配可以拆成一对I-O和一对I-I,显然也是不劣的。
据此,我们需要转移的情况只有 \((j,i]\) 中的所有 I 都和 \(j\) 及其前面的 O 匹配在一起。我们考虑找到前面第一个有足够多 O 的地方,这样产生一堆 I-O 匹配之后,匹配中间跨越的 I 受到上述性质的影响需要继续向前找 O 进行匹配。所以我们最终会找到最大的一个 \(p\) 使得 \([p,i]\) 中 I 和 O 数量相等,从 \(f_{p-1}\) 转移而来,加上中间所有 I 的下标和。
显然使用 map 辅助即可。时间复杂度 \(\mathcal O(n\log n)\)。
P13004 [GCJ 2022 Finals] Schrödinger and Pavlov
概率论好难呀。
尝试直接 dp 这个东西,然后发现非常麻烦,我们要提前确认有些位置是否有猫,这样贡献之间处理起来很难受。
转成期望 dp。设 \(f_i\) 表示当前局势下 \(i\) 盒子中有猫的期望,也就是概率,那么我们一步一步模拟过去即可,模拟过程中需要用到 \(c,b_c\) 当前局面的概率来计算下一局面的概率。
然而这是不对的。考虑整个东西构成一个内向基环树森林,那么有可能一开始 \(i\) 盒子的概率影响往后传递,绕了一个圈之后 \(i\) 盒子的概率又影响到了连到 \(i\) 的那个盒子,这样的双向影响显然是会导致计算错误的(第一次之后没猫的不能和第二次有猫的概率放在一起)。
考虑断环处理。可以发现我们必须断掉环上编号最小的点 \(c\) 它的出边,否则 \(c\) 第一次的影响就会开始往后传递,这样就会转回来产生影响了,我们不希望这样。
然后考虑断环之后怎么处理断边的问题。因为我们必须转移这些边,但是要避免 \(c\) 回到自己。我们考虑把 \(c\) 和 \(b_c\) 的贡献固定下来,直接确定上面是否有猫,这样就是对应概率和对应概率放在一起,有猫和有猫的概率一起打包算,没猫和没猫的概率一起打包算。算出概率之后再乘上两边分别有猫/没猫的概率累给答案即可。
10.26 T2 - マシュマリー
首先有一个显然的 dp \(f_{i,j}\) 表示现在已经取出了 \(i\) 个不同的球,其中 \(j\) 个是取出来恰好一次的。那么 \(f_{i,j}\) 转移到 \(f_{i,j},f_{i+1,j+1},f_{i,j-1}\),移项一下 \(f_{i,j}\) 就能转移了。注意 \(i=n\) 时不要同层转移,因为到达 \(i=n\) 时直接结束过程了。
然后考虑这个答案的结构肯定是 Stirling 转下降幂,我们知道 \(x^i=\sum\limits_{j=0}^x{x\choose j}\begin{Bmatrix}i\\ j\end{Bmatrix}j!\)。现在考虑对于每个 \(j\le m\) 怎么算 \(\mathbb{E}({x\choose j})\)。
考虑用组合意义反过来说这个,我们钦定 \(j\) 个球被取出来恰好一次,那么剩下的球都不管的概率和就是这个东西。
不妨设 \(g_{i,j}\) 表示现在已经取出了 \(i\) 个不同的球,我们钦定了 \(j\) 个球是取出来恰好一次的,剩下不管。那么转移就考虑:
- \(g_{i,j}\to g_{i,j}\),拿到了 \(i-j\) 个球中的一个,没有影响。
- \(g_{i,j}\to g_{i+1,j}\),拿到了 \(n-i\) 个球中的一个,不钦定它取出来恰好一次,那就不管他了。
- \(g_{i,j}\to g_{i+1,j+1}\),拿到了 \(n-i\) 个球的一个,然后钦定它是取出来恰好一次的那个。
最后 \(g_{n,j}\) 就是 \(\mathbb{E}({x\choose j})\),带回去。不允许钦定超过 \(m\) 个球即可做到 \(\mathcal O(nm)\) dp 出来。
10.26 T3 - 交换
我好蠢。。不会做结论题了。
考虑整个东西是在一个完全二叉树上做,我们一层一层扫过去可以选择把一个数和它的父亲交换,最后让字典序最小。
先考虑根部。很明显对一个
扫完之后我们可以得到以下四种可能,之后两个儿子子树又独立了:

对于 \(a\) 和 \(b\) 为三者中最小值的情况,我们可以无脑向下。问题在于我们要对 \(c\) 做最小值的情况决策 \(a,b\) 的顺序。
Lemma. 不妨设 \(a<b\)。那么 \(a\) 在某个子树做根更好当且仅当这个子树的最优解中 \(a\) 所在的位置小于等于放在另一个子树。
Proof.
我草这太厉害了。
先考虑第一件事。对于固定的一个子树,可以说明根较大的时候这个子树的字典序一定会变大。反证容易,如果存在一种方式字典序变小,则根较小的情况可以盗窃这种策略,从而字典序会更小。
然后我们考虑,对于同一个固定的子树的两种根的值 \(a,b\),我们可以说明 \(a<b\) 时比出两种序列字典序的位置一定是 \(a\) 所在的位置。证明同样可以类似的反证:在这个位置之后显然不可能(\(b\) 为根时树里不可能有 \(a\)),在这个位置之前则可以让根的值为 \(b\) 时盗窃这种策略。
然后回到原结论,我们实际上是有四个序列:\(a,b\) 为左子树根,\(a,b\) 为右子树根。实际上我们在逐位比较 \(a\) 左 \(b\) 右和 \(b\) 左 \(a\) 右两个序列按照相同模式交叉的结果。根据上面的结论,\(a\) 左 \(b\) 左一定在匹配一个相同的前缀直到出现 \(a\),\(a\) 右 \(b\) 右同理,所以最终比出大小更小的一定是 \(a\) 所在的一个位置,那么显然是谁的 \(a\) 更靠前谁小了。
然后这个事情就很容易了。我们希望知道某个子树以某个值为根,这个根最后会到达哪个位置。考虑直接 \(f_{i,j}\) 表示以 \(i\) 为根的子树以 \(j\) 为根会到达的位置,我们可以直接 \(\mathcal O(n^2)\) dp 上去。
但我们不要这样做。我们考虑每个点上实际上没有太多的状态会被用到,因为它上面至多产生 \(\mathcal O(\log)\) 个询问(它到根的链和这条链的邻域上的值),每个询问至多导致他所在的整棵子树刷一遍它这个值的状态,所以实际上每个点上只会产生 \(\mathcal O(\log)\) 个状态,最后总状态数是 \(\mathcal O(n\log n)\),用 unordered_map 或者别的什么东西记忆化一下就好了。
异或和
哎我忘记那个结论了……
先考虑刻画所有子序列的异或和之和这回事。我们显然需要掏出一个拆位,于是:
其中 \(cnt_0,cnt_1\) 表示这一位上为 \(0\) 和为 \(1\) 的数的数量。
回忆 APIO2024 在余姚的江边散步买扑克牌时 SA 科普的结论。组合数上 \(n>0\) 的一行中偶数位置的和和奇数位置的和是相等的,都是 \(2^{n-1}\)。所以我们可以把最后那个组合数打开。
当然,这只对 \(cnt_1>0\) 的位置成立。所以我们可以把子序列的异或和之和直接写成:
所以本质上我们只是想知道 \([l,r]\) 中随意选一个大小不超过 \(n\) 的子集的按位 \(\operatorname{OR}\)。
然而事实上我们可以用两个数表示其任意子集的按位 \(\operatorname{OR}\)。考虑子集中所有数从高到低第一个不一样的位 \(k\),我们取一个数来满足这一位,后面全 \(0\),这样只要存在一个数这一位为 \(0\),然后我们把所有的数这一位归 \(0\) 全部或起来就行。
所以问题变成在 \([l,r]\) 里面选两个数,考虑有多少种不同的按位或。
我们(应该?)有若干 \(\log\) 比较多的做法,但我们考虑 1log。
首先我们肯定可以取到 \([l,r]\) 中的所有数,但是我们应该还能取到 \((r,r\ \operatorname{OR}\ (2^k-1)]\) 中的一些数。经过手玩实际上就是不会证,搞不出来可以发现,我们严肃取不到 \((r\ \operatorname{OR}\ (2^{m+1}-1),l\ \operatorname{OR}\ 2^k)\) 中的数,其中 \(m\) 是 \(r\) 在 \(k\) 之后第一个 \(1\) 的位置。
注意一些特判,还有取不到的区间有可能是空的。

浙公网安备 33010602011771号