save
树上的数据结构
附录:
前置知识
树的三种序:dfs 序,欧拉序,括号序。
\(O(n\log n) -O(1)\) LCA,\(O(n) - O(\log n)\) LCA。
点 / 边双连通分量,缩点。
kruskal,boruvka?
目录:
- 生成树相关
- 链剖分 和 dsu on tree
- 点 / 边分治与虚树
- 笛卡尔树和 kruskal 重构树。
- 动态树相关。
生成树相关
kruskal 和 prim 求最小生成树大家都很熟悉了,这里来讲一讲 boruvka 算法:
boruvka 的算法流程是:每一轮,对于每个点,求出与它不在同一个连通块的点的最小边权。每个连通块选择最小的权值连边。
每次操作至少减少一半的连通块。
设“寻找一个与其相连的最小异连通块”的复杂度为 \(O(f(n))\),总时间复杂度 \(O(nf(n)\log n)\)。
当两点之间的边权为一些特殊值时很有用。
例题:
【UOJ176】新年的繁荣
\(n\) 个点,每个点有一个属性 \(a_i\)。\(x, y\) 之间的边权为 \(a_x \ \mathrm{and} \ a_y\) ,求此图的最小生成树。
AT3611 Tree MST
\(n\) 个点的树,有一张完全图,其中 \(x,y\) 的边长为 \(\mathrm{dis}(x,y)+w_x+w_y\),求该图的最小生成树。
链剖分
树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。
重链剖分
重链剖分可以将树上的任意一条路径划分成不超过 \(\log n\) 条连续的链,每条链上的点深度互不相同。
重链剖分还能保证划分出的每条链上的节点 DFS 序连续,因此可以方便地用一些维护序列的数据结构(如线段树)来维护树上路径的信息。
例题:
LOJ6669 Nauuo and Binary Tree
[GXOI/GZOI2019]旧词
长链剖分
长链剖分的重儿子变成了深度最大的子节点。其他和重链剖分一样。
长链剖分后,一个点 \(x\) 的 \(k\) 级祖先 \(y\) 的长链长度 \(\geq k\)。
因此,一个点 \(x\) 不断跳跃长链到达根节点,切换长链次数为 \(O(\sqrt {n})\) 级别。
例题:
CF526G Spiders Evil Plan
长链剖分优化 dp
在涉及一些以深度为下标的 dp 转移时,长链剖分可以将这些转移优化成线性。
一般长链剖分优化 dp 的流程是:在 dp 过程中,将重儿子的信息 \(O(1)\)继承,此时所有的轻儿子的信息的下标不会超过重儿子的下标,直接暴力将轻儿子的信息合并到重儿子。
使用指针 \(O(1)\) 继承,由于每条重链都只会暴力统计 1 次,时间复杂度 \(O(n)\)。
空间能开大就尽量开大,防止神必原因 RE。
[POI2014]HOT-Hotels 加强版
太经典了。
考虑两辆深度相同的三个点呈什么形状分布,继而设计 dp 状态。
Dsu on tree
Dsu on tree,又称树上启发式合并,适用于离线地对于子树 / 路径的信息进行非常暴力直接地维护。
Dsu on tree 的算法流程如下:
- 进行轻重链剖分求出重儿子,在处理询问时先遍历轻儿子,最后将它们的信息撤销。
- 遍历重儿子,不撤销信息。
- 再遍历轻儿子,加入信息。
一个节点被遍历的次数等于包含于它的轻子树的个数,显然为 \(O(\log n)\) 次,所以总增加 / 撤销的次数为 \(O(n \log n)\)。
CF1709E XOR Tree
UOJ #284 快乐游戏鸡
虚树
虚树用来解决给定关键点之间的路径信息。
虚树的构建:将所有点按照 dfs 序排序,实时维护一个从根节点出发的链。加入一个点 \(x\) 时,分类讨论:
- 当 \(x\) 可以直接加入这条链时或者栈为空,直接加入。
- 否则,设 \(x\) 和栈顶的 lca 为 \(p\),不断弹出 \(dep_z \geq dep_p\) 的点,并加边。然后将 \(p\) 和栈顶连边后将栈顶设为 \(p\),最后加入 \(x\) 。
虚树的推论:
- 点集 \(a_1, a_2,\dots, a_k\) 形成的虚树边权和为按照 dfs 序排序后相邻两点的距离之和,也就是 \(\dfrac 1 2(\sum\limits_{i = 1}^{k- 1}dist(a_i,a_{i+1})+dist(a_1,a_k))\)
- 一个点 \(x\) 到关键点的 lca 深度最小值为其在 dfs 序上的前驱后继取 \(\min\)。
例题:
【AHOI2022】钥匙
注意到每个颜色可以分开算贡献。要考虑怎么设计一个点对的匹配贡献才不会不重复计算。
发现每种颜色的钥匙很少,而一次贡献又要一把钥匙匹配一个箱子,可以想到“括号序”的方式, 把钥匙看作左括号, 箱子看作右括号。
对于每种颜色建出虚树,枚举可能的钥匙作为起点,当恰好左右括号匹配时,两端在两个子树内的询问点会有贡献,是一个区间的形式,二维数点扫描线即可。
CF809E Surprise me!
首先需要知道:\(\varphi(xy)= \dfrac{\varphi(x)\varphi(y)\gcd(x,y)}{\varphi(\gcd(x,y))}\) ,然后得到:
\(ans = \sum\limits_{i}\sum\limits_{j}\dfrac{\varphi(a_i)\varphi(a_j)\gcd(a_i,a_j)}{\varphi(\gcd(a_i,a_j))}\times dist(i,j)\)。
枚举 gcd :\(ans = \sum\limits_{d} \sum\limits_{t}\mu(t)\dfrac{d}{\varphi(d)}\sum\limits_{dt|a_i}\sum\limits_{dt|a_j} dist(i,j)\varphi(a_i)\varphi(a_j)\)
预处理 \(g_d = \sum\limits_{d|a_i}\sum\limits_{d|a_j}dist(i,j)\varphi(a_i)\varphi(a_j)\) ,可以通过每次剑虚树统计得到。然后再做一遍狄利克雷卷积就是答案。
一个点最多被加入 \(\sqrt n\) 个虚树,时间复杂度 \(O(n \sqrt n \log n)\),实际上远远跑不满。
LGP8147 [JRKSJ R4] Salieri
建出 AC 自动机,对于一个询问 \((S,k)\) 而言,相当于有 \(|S|\) 次从 fail 树上一个点到根的路径加。
对形成的连通块建出虚树,二分答案 \(mid\),相当于询问虚树上有多少个点的权值 \(v \geq \left\lfloor\dfrac{mid}{siz}\right\rfloor\),使用主席树维护。
树分治
静态树分治
树分治用来处理所有路径的信息的问题。
类似序列上的分治找中点,树的中点是什么呢?就是树的重心。
点分治的具体流程如下:找到当前连通块的重心 \(p\)(可以一次树形 dp 求得),统计在这个连通块内经过重心路径的信息。然后将重心删除,对于剩下的几棵子树递归上面的过程。
由于删去重心后剩下的所有连通块大小 \(S'\) 不会超过当前大小 \(\dfrac S 2\),因此分治树的层数最多为 \(\log n\), 设统计经过根的信息的复杂的为 \(f(n)\),总时间复杂度为 \(O(n f(n) \log n)\)。
当强制经过某一点的路径信息不好求得时,若维护信息具有可减性,利用容斥的思想,可以先计算这个连通块内所有点对路径的答案,在对删去根后的所有儿子 \(y\), 减去 \(y\) 连通块的答案。此时求得的就是强制经过根节点的答案。
例题
[BJOI2017] 树的难题
预处理每个点到分治中心对应子树的颜色权值。在拼接的时候分颜色是否相同考虑,如果相同还要而外减去对应颜色的权值。
考虑开两棵线段树分别维护与当前点同色 / 不同色的权值。把分治中心的所有儿子按照颜色排序后,相同的颜色对应相同的区间。若为两个颜色的交界处直接把同色的信息合并到异色。这个操作可以用线段树合并来完成。
查询时就是区间 \(\max\),可以直接维护。
时间复杂度 \(O(n \log^2n)\)。
[CTSC2018]暴力写挂
将答案式乘 2 变成:\(\mathrm{dis}(x,y)+\mathrm{dep}_1(x)+\mathrm{dep}_1(y) - 2\mathrm{dep}_2(\mathrm{lca}(x,y))\)。
考虑点分治,设一个点 \(x\) 的权值为 \(w(x) = \mathrm{dep}(x)+\mathrm{len}(x)\), 其中 \(\mathrm{len}(x)\) 表示 \(x\) 到分治重心的距离。
因为答案还和 \(x,y\) 在第二棵树上的 lca 有关,考虑把分治涉及到的这些点建出虚树,枚举 \(\mathrm{lca}\), 答案就是不在同一个子树内(第一棵树上),而且在 lca 的不同子树内(第二棵树上)的最大值,对于虚树上的点维护最大值和不为最大值颜色的次大值即可。
时间复杂度 \(O(n \log^2 n)\), 瓶颈在于对虚树上的点的 dfn 排序。
[WC2018]通道
现在两棵树变成三棵树了,但是保证边权非负。
我们将对第一棵树进行点分治改为边分治,保证只有两种不同的颜色方便合并。
仍然对第二棵树建出虚树,问题就在于如何维护第三棵树上的点对距离。
我们设一个点对 \((x,y)\) 的“距离” 为 \(val_x +val_y + \mathrm{dis}_3(x,y)\),其中 \(val_x = \mathrm{dep}_1(x)+\mathrm{len}(x)+\mathrm{dep}_2(x)\), 数组的定义和上面的题一样。对于每一个 lca,我们要求不同子树内的 “距离”最大值。
你可能很奇怪为什么我要定义一个距离而不是权值,实际上,由于边权非负,直径的信息是可以合并的。
具体地,设 \(S_1,S_2\) 为两个点集,设它们直径的端点分别为 \((a, b)\) 和 \((c,d)\), 则 \(S_1 \cup S_2\) 的直径只可能是 \(a,b, c,d\) 任意组合后得到的最大值。
查询时就分别把黑色点和白色点的直径端点两个两两拼接取 \(\max\) 即可。
时间复杂度 \(O(n \log^2 n)\)。
动态树分治
对于单次全局询问,可以使用点分治。若要修改或者多次询问呢?
将点分治每次的重心按照遍历顺序建立父子关系,可以得到一棵新树,称为点分树。
由于点分治最多进行 \(\log n\) 轮,因此点分树的深度为 \(\log n\) 级别。这意味着我们可以从一个点暴力跳到根节点,通过在每个点维护一些信息,可以方便地将点分治的过程动态化。
以 震波 为例:
给定一棵树,每个点有点权。支持单点修改,或者询问一个点 \(x\) 距离不超过 \(k\) 的连通块的权值和。
对于一个分治重心,维护一棵以到重心的距离为下标的线段树,表示距离为 \(k\) 的点的点权之和。
对于单次询问 \((x,k)\),先统计 \(x\) 作为分治重心的答案,再不断跳父亲 \(fa\),统计 \(fa\) 的连通块内除去 \(x\) 的连通块的信息,也就是距离 \(fa\) 不超过 \(k - dist(x,fa)\) 的点权。
为了做到这点,额外维护每个点的连通块到其分治父亲的线段树,那么在查询时就可以用父亲的总信息减去父亲对儿子的信息。
在修改时,同时修改这两个线段树即可。
时间复杂度 \(O(n \log^2 n)\)。
[ZJOI2007] 捉迷藏
保存每个点到分治重心的最大距离和次大距离,拼起来就是答案。 用可删堆保存。
维护每个点到父亲的最大距离,在加入一个点时,先删去对父亲的影响,在再到父亲的距离的堆里面加入,再更新父亲对全局答案的影响。
kruskal 重构树
kruskal 重构树用来解决树 / 图上路径的最值问题。
我们将 kruskal 的过程改写:把边从小到大排序后,若 \((u, v)\) 不连通,我们新建节点 \(p\), 将 $u,v $ 的父亲设为 \(p\),继续操作。这样子得到的一棵树叫做重构树。
一般情况下我们是对边建出的重构树,当然也可以对点进行操作,若要求 \(\leq d\), 就把边 \((u,v)\) 的权值设为 \(\max(w_u,w_v)\) \(\geq d\) 同理。
性质:
-
一般情况下是是一棵二叉树。
-
原图的所有节点是重构树上的叶子节点。
-
对于节点 \(u\) 和其父亲节点 \(v\), 满足相同的偏序关系,即父节点的权值总不大于儿子的权值或总不小于儿子节点。因此 \(u \to v\) 上的边权最大 / 最小值为重构树上的 LCA 节点
求解节点 \(x\) 在经过边权不超过 \(d\) 的边所能到达的连通块,就是在重构树上 \(u\) 的最浅祖先满足其权值 \(\geq d\) 的子树。
[NOI2018] 归程
建出重构树后倍增,就变成了子树最小值。
[IOI2018] werewolf 狼人
人形态只能走 \(\geq L\) 的点权,狼形态只能走 \(\leq R\) 的点权,我们只需要分别对人和狼建出一棵重构树后倍增跳到对应节点后,问题变成了两段区间 \([L_1, R_1]\), \([L_2, R_2]\) 是否有交集。
将节点 \(p\) 在第一棵树上的位置 \(pos_i\) 作为下标按照第二棵树的顺序建出线段树,问题又变成 \([L_2, R_2]\) 中是否存在 \([L_1, R_1]\) 的数,主席树即可。
时间复杂度 \(O(n \log n)\)。
BSOJ7688 超级加倍
分别对最大最小建出重构树后,问题等价于在第一棵树上 \(x\) 为 \(y\) 的祖先, 第二棵树上 \(y\) 为 \(x\) 的祖先的 \((x,y)\) 的数量,树状数组统计。
笛卡尔树
笛卡尔树用来解决序列上的最值问题。
笛卡尔树是一棵二叉树,其每一个点有两个键值 \((k, w)\),其中 \(k\) 满足二叉搜索树(中序遍历为原数组)的性质,\(w\) 满足堆(父亲和儿子节点满足相同的偏序关系)的性质的二叉树。
通常对一个序列建笛卡尔树,就是将它的下标作为二叉搜索树的键值,权值 \(val\) 作为堆的键值。
性质
- 一定是棵二叉树,而且当点权互不相同时,笛卡尔树唯一。
- 笛卡尔树上的节点 \(x\) 的子树对应序列上连续的一段。
- 笛卡尔树本质上是一种不平衡的 treap,当权值随机时,其也具有 treap 深度为 \(\log n\) 的性质,因此可以用 treap 来维护笛卡尔树。
构建算法:假设我们要建大根堆的笛卡尔树,实时维护一个栈表示当前最靠右的链节点,其值单调递减。
加入到 \(x\) 时,不断弹出 \(\leq w_x\) 的节点,设最后一个弹出的节点为 \(lst\), 将 \(x\) 的左儿子设为 \(lst\)。设当前栈顶为 \(z\), 将 \(z\) 的右儿子设为 \(x\)。 加入 \(x\)。
for(int i = 1; i <= n; ++i) {
c[i] = read();
while(tp && c[stk[tp]] <= c[i]) lc[i] = stk[tp --];
if(tp) rc[stk[tp]] = i; stk[++tp] = i;
}
[HNOI2016]序列
对于一次询问 \([l,r]\), 我们找出其最小值位置 \(p\),那么经过 \(p\) 的最小值显然就是 \(a_p\),贡献为 \((p - l+1) \times (r - p+1) \times a_p\),再考虑不经过 \(p\) 的区间。
设 \(f_i\) 表示以 \(i\) 结尾的所有区间的最小值之和,转移考虑找到在单调栈的栈顶结点 \(j\),显然有 \(f_i = f_j+(i - j) \times a_i\)。
对于 \((p,r]\) 这个区间,显然答案可以写成 $\sum\limits_{i = p+1}^{r}f_i - f_{p} $,记一个前缀和数组即可 \(O(1)\)。
对于 \([l,p)\) 这个区间同理,我们只用维护后缀和即可。
时间复杂度 \(O(n \log n)\),瓶颈在于区间最值。
CF1117G Recursive Queries
显然,一个区间 \([l,r]\) 的答案为将 \([l,r]\) 中元素建笛卡尔树后,每个点的深度之和(假设根节点深度为 1)
将询问离线按照右端点排序,实时维护 \([1,r]\) 构成的笛卡尔树。
而区间 \([l,r]\) 的笛卡尔树的根就等于这条右链上第一个编号 \(\geq l\) 的点。它的子树就是 \([l,r]\) 的笛卡尔树的右儿子。
现在我们只需要实时维护每个点的深度即可,注意到若当前新插入 \(x\),当前栈顶为 \(p\),则 \(x\) 的左儿子区间为 \([p+1, x - 1]\), 将这些点的深度 + 1 即可,\(x\) 的深度就等于当前栈的元素个数。
当然这样只维护了右儿子,对于左儿子,将数组翻转后再做一次即可。
使用线段树维护区间加,时间复杂度 \(O(n \log n)\)。
P5044 [IOI2018] meetings 会议
设 \(dp_{l,r}\) 表示将编号在 \([l,r]\) 的人聚集起来的最小花费,设 \([l,r]\) 的最大值位置在 \(p\),显然我们不可能在 \(p\) 点举行会议,这样显然不优,则有转移:
\(dp_{l,r} \leftarrow \min(dp_{l,p - 1}+(r - p+1) \times a_p, dp_{p+1,r}+(p - l+1) \times a_p)\)
由于 dp 涉及区间最值的位置,考虑建出笛卡尔树。设询问 \([l,r]\),我们只要求出 \(dp_{l, p - 1}\) 和 \(dp_{p+1,r}\) 取 \(\min\) 。按照上面一个题的套路,后者将整个序列翻转后再求解一遍,于是我们只考虑右儿子也就是 \(dp_{p+1,r}\) 的求解。
设当前在笛卡尔树的 \(p\) 点,设 \(p\) 管辖的范围为 \([l,r]\),实时维护 \(dp_{l, i}, i \in[l,r]\)。
假设当前已经把左右儿子的 dp 值求出来了,考虑合并,观察上面的柿子,等价于 \([l,p - 1]\) 整体加上一个一次函数,\([p+1,r]\) 整体加后对一个一次函数取 \(\min\)。
而 \(dp_{l,i}\) 随 \(i\) 的增大单调不降,而且“斜率” 显然要比 \(a_p\) 小,我们可以证明 \([p+1,r]\) 和这个一次函数只有最多一个交点。
由于只有一个交点,被这个一次函数更新的一定是一段区间,于是直接用线段树维护区间加,区间对一个只有一个交点的一次函数取 \(\min\) 。
实现细节可以对每个区间 \([l,r]\) 保存其端点也就是 \(l\) 和 \(r\) 的值,对一个一次函数取 \(\min\) 时当且仅当这个一次函数在 \(l, r\) 的取值都小于当前取值才更新。
时间复杂度 \(O(n \log n)\)。
CF1603F
分类讨论 \(x\) 是否为 0。
当 \(x = 0\) 时,问题相当于值域在 \([1,2^{k - 1}]\),秩为 \(n\) 的数组数量,第一个位置方案数为 \(2^{k} - 1\),第二个位置为 \(2^{k}-2, \dots\)。以此类推,于是答案是 \(\prod\limits_{i = 1}^{n}(2^k - 2^{i - 1})\)。
当 \(x \neq 0\) 时,对于每个 \(x\) 答案是一样的,不妨假设 \(x = 1\),将 \(x\) 放在第一个位置后再加入 \(n\) 个数。于是设 \(f_{n,r}\) 表示 \(n\) 个数,秩为 \(r\) 的方案,于是有转移:\(f_{n,r} \leftarrow f_{n - 1,r} \times 2^{r - 1}+f_{n - 1, r - 1} \times (2^k - 2^{r - 1})\)。
答案即是 \(\sum\limits_rf_{n+1,r}\)。
设 \(F_r(x) = \sum\limits_{n}f_{n,r}x^n\),于是有 \(F_{r}(x) = F_r(x) \times x \times 2^{r - 1}+F_{r - 1} \times x \times (2^k - 2^{r - 1})\),即 \(F_r(x) = x^r \times \prod\limits_{i = 1}^{r}\dfrac{2^k - 2^{i - 1}}{1 - 2^{i - 1}x}\),将 \(F_r(2x)\) 和 \(F_r(x)\) 比较发现 \(F_r(x) = F_r(2x) \times \dfrac{1 - 2^rx}{1 - x}\),提取系数后得到 \(f_n = \prod\limits_{i = 1}^{n}\dfrac{2^{i+r - 1} - 1}{2^i - 1}\)。
答案就是 \(\dfrac{1}{2^k - 1}\sum\limits_r \prod\limits_{i=1}^{n-r+1}\dfrac{2^{i+r - 1} - 1} {2^i - 1}\)。
CF1726E Almost Perfect
ARC120F / F2
设 \(f_{n,k}\) 表示在长度为 \(n\) 的序列中选出 \(k\) 个不相邻位置的方案,显然有 \(f_{n, k} = f_{n - 1, k}+f_{n - 2, k - 1}\), 通过简单的生成函数运算发现 \(f_{n,k} = \dbinom{n - k+1}k\)。
于是答案可以表示成 \(\sum\limits_{i=0}^{k - 1}f_{m_1, i} \times f_{m_2, k - i - 1}\)。可惜的是,虽然看起来很像范德蒙德卷积,但并不能化简。 于是寄了。
考虑把序列化环,设 \(G(n,i,k)\) 表示长度为 \(n\) 的环中,第 \(i\) 个位置必须选,总共选择 \(k\) 个的方案。
由于环旋转是同构的,于是有 \(G(n, 1, k) = G(n, 2, k) = \dots =G(n, n, k)\),不妨设为 \(F(n,k)\)。
而 \(F(n,k)\) 可以强制将第一个位置设为选择得到通项:
\(F(n, k) = \begin{cases} [k \leq 1] \ \ \ \ \ n < 3 \\ f(n - 3, k - 1) \ \ \ \ \ \ n \geq 3\end{cases}\)
再考虑将环转化成序列,当序列首尾元素没有同时被选择时是肯定是个双射,只用考虑首尾都被选择的情况,此时还剩下 \(n- 4\) 个位置,\(k - 2\) 个数,于是有:
\(ans(n, i, k) = \begin{cases} 0 \ \ \ \ \ \ \ n \or i \or k \leq 0 \\ F(n,k)+f(n - 4, k - 2) \ \ \ \ \ \ i = 1 \\ F(n,k)+ans(n - 4, i - 2, k - 2) \ \ \ \ \ \ i > 1 \\ ans(n, n - i +1, k) \ \ \ \ \ \ \ i > \left\lceil\dfrac n 2 \right\rceil \end{cases}\)
若没有 \(i\) 的约束,展开后就是 \(F(n, k) +F(n - 4, k - 2) + \dots\) ,于是可以预处理下前缀的 \(F\) 后对 \(i\) 分别是奇偶讨论。
CF1753D
CF1732F
BS8187 可重集计数
BS8181 周黑鸭 D
BS8177 进制D / loj510 北校门外的回忆
LG8558 黑暗(Darkness)
LG8559 寻宝(Treasure)
LG8560 约定(Promise)
P5320 [BJOI2019]勘破神机
用 \(1 \times 2\) 和 \(2 \times 1\) 的骨牌铺满 \(2 \times n\) 的方格的方案为 \(f_{n+1}\),其中 \(f_0 = 0, f_1 = 1\)。
而 \(f_n = \dfrac{\sqrt{5}}5((\dfrac{1+\sqrt 5}2)^n - (\dfrac{1 - \sqrt 5} 2)^n)\)。
铺满 \(3 \times n\) 的骨牌方案为 \(g_n = 3g_{n - 2}+2\sum\limits_{k \geq 2}g_{n - 2k}\),将下表除以二,使用简单的特征根解得:
\(g_n= \dfrac{3+\sqrt 3}6(2+\sqrt 3)^n+\dfrac{3 - \sqrt 3}6(2-\sqrt3)^n\),设为 \(f_n = Ax^n+By^n\)。
答案是 \(\sum\limits_{n = l}^{r}\dbinom{f_n}k = \dfrac 1 {k!}\sum\limits_{n = l}^{r}f_n^{\underline k}\),利用第一类斯特林数展开下降幂得到:
\(=\sum\limits_{n = l}^{r}\sum\limits_{i= 0}^{k}\begin{bmatrix} k \\ i \end{bmatrix}(-1)^{k - i}f_n^i = \sum\limits_{i = 0}^{k}\begin{bmatrix} k \\ i \end{bmatrix}(-1)^{k - i}\sum\limits_{n = l}^{r}f_n^i = \sum\limits_{i = 0}^{k}\begin{bmatrix} k \\ i\end{bmatrix}(-1)^{k - i}\sum\limits_{n = l}^{r}\sum\limits_{j = 0}^{i}\dbinom i j A^jB^{i - j}(x^jy^{i-j})^n\)
\(=\sum\limits_{i = 0}^{k}\begin{bmatrix} k \\ i\end{bmatrix}(-1)^{k - i}\sum\limits_{j = 0}^{i}\dbinom i jA^jB^{i - j}\sum\limits_{n = l}^{r}(x^jy^{i - j})^n\)。
扩域,等比数列求和 \(O(k^2 \log k)\)。
UOJ#50 链式反应
将原子裂变的过程建出一棵有根树,要求儿子节点编号大于父亲,且一个点的儿子个数 \(s = c+2(c \in S)\),其中有 \(c\) 个儿子为叶子节点,\(2\) 个儿子任意。
设 \(f_n\) 为 \(n\) 个点的答案,枚举根的两个儿子可得:\(f_n = \dfrac 1 2\sum\limits_{i}\sum\limits_{j}\dbinom{n - 1}{i+j}\dbinom{n - 1 - i}{j}f_if_j[n - 1 - i - j \in S]\)
有 \(F' = F^2G+1\),全半在线卷积。
贪心,由于 \(B <C <A\),相邻两个快车站之间的最短路一定是全部走 B,在它们之间的列车贪心地先走 A,走到不能走了就只能走 B。模拟即可。
二分极差。一个省的选择方案一定是单调不增的,记录两个省的 mx 和 mn,贪心选择。
由于一定存在一整行或一整列被选择的情况,只需要对四个方向都做一遍就是对的。
结论题。
首先染色可以在翻折之前就染完,这样一定不劣于边翻折边染色。于是我们就要判断颜色数量为 2 的序列是否合法。
结论:一个序列合法当且仅当 除了首尾颜色连续段外的其他颜色段长度均为偶数。
证明:
- 充分性:若只剩下两段显然成立。否则将最后一段的长度变为 1,将序列沿倒数第二段中点对折,重复操作直到剩下两段。
- 必要性:若存在长度为奇数的非首尾段,那么翻折一定不会在这一段进行。而翻折其他段,这个段仍然会有两个异色段相邻,于是不可能剩下两个段。
有了这个结论后,将长度为偶数的段拆成若干个长度为 2 的段,枚举第一段的位置(只有可能是 1 或者 2 开头),对于单个的颜色 \(c\) 答案就是:\(\min_{j \neq i}n - cnt_i - cnt_j +f_{i,j}\),其中 \(f_{i,j}\) 表示长度为 2 的段的颜色分别为 \(i,j\) 的段的个数。
对于每一个 \(j \neq i\) 维护 \(f_{i,j} - cnt_j\) 的最大值。每次只用动态加 \ 删一个桶,时间复杂度线性。
贪心选择前 \(k\) 大的空隙即可。
按照画框从大到小排序后,按照美观度从大到小加入画,若当前画框能匹配画则加入。
正确性显然。
若 \(a_i\) 不是 \(a_{i - 1}\) 的倍数,将 \(a_i\) 改成 \((\left\lfloor\dfrac{a_i}{a_{i - 1}}\right\rfloor +1)a_{i - 1}\) 不会影响答案。因此本质不同的 \(a_i\) 只有 \(\log\) 个。于是把 \(a\) 相同的区间缩起来。
模拟队列行进的过程可以发现,一个步伐为 \(a_i\) 的人只会走 \(a_i\) 的倍数距离,且若经过时间为 \(t\),走过的距离为 \(\left\lfloor\dfrac{a_i}t\right\rfloor \times t\)。由于不同的 \(a_i\) 只有 \(\log n\) 个,每一段都是一个区间,于是直接暴力判断即可。
由于没有什么显然无解的情况,于是猜测所有情况都有解。
考虑怎么贪心,一定是越靠前的位置分给的越多的人越好,设 \(pos_{i,j}\) 表示只考虑第 \(i\) 个人,把整个馕平均分成 \(n\) 份时第 \(j\) 份的结束位置。
枚举每一段,贪心选择未被得到馕的且结束位置最靠前的人。
每循环一圈,\(s\) 变成了 \(\dfrac s {2^n}\),模拟 \(\log V\) 轮就好了。
阴间思维题。
首先把从 \(A \to B\) 的旅程看做要么 \([A,B) + 1\),要么 \([1,n] \ / \ [A,B]+1\),问题就是使得序列的最大值最小。
直接二分最大值,然而不会检验,遂寻求一些性质。
不妨让所有请求都选择 \([A,B)\),设 \(a_i\) 表示当前的数列, \(b_i\) 表示选择一些区间翻转后的答案序列。
-
性质 1:所有翻转的序列两辆有交。
说明:若区间无交,显然不翻转不比翻转劣。
-
性质 2:设所有翻转区间的交集为 \([l,r]\),设 \(t\) 表示 \(a_{l \dots r}\) 中最大的下标,则有 \(b_t \geq \max b_i - 1\)。
说明:可以感性理解为每次翻转都要包含最大的元素,只不过可能需要微调。当 \(l \leq i \leq r\) 时显然成立,否则任意撤销一个翻转区间,答案不变劣。
-
性质 3:\(t\) 满足 \(a_t = \max a_i\)。
说明:仍然考虑反证法,当 \(l \leq t' \leq r\) 显然成立,设 \(a_t - b_t\) 表示经过 \(t\) 的翻转区间的个数,则有\(a_t - b_t \geq a_{t'} - b_{t'}+1\),得到 \(a_t+b_{t'} \geq b_t +a_{t'} + 1\),与性质 2 矛盾。
根据上面的结论,可以开始二分答案 \(cnt\)。 根据性质 3,可以先找到 \(a\) 序列中的 \(t\)。
此时翻转个数 \(num\), 要么等于 \(a_t - cnt\),要么等于 \(a_t - cnt+1\),分别检验。
然后需要将所有 \(l \leq t, r \geq t\) 的区间按需求翻转,从 \(1 \to t\) 从小到大扫描线,若当前翻转了 \(p\) 个区间,则当前的 \(b_i = a_i - p +cnt - p\),若 \(b_i > num\),则不得不贪心地把最靠右的右区间翻转,最后再检验一下 \([t+1, n]\) 是否合法。
结论很抽象,二分答案的过程很奇怪,不愧是你 JOI。
LG7718 「EZEC-10」Equalization
显然转化成长度为 \(n - 1\) 的差分序列,每次可以对一个点单点修改,或者对两个点 \(i, j\) 执行 \(a_i \leftarrow a_i+x, a_j \leftarrow a_j - x\) 的过程。
先考虑最少操作次数怎么求,注意到和为 \(0\) 的一个子集 \(S\) 可以只用 \(|S|- 1\) 次操作即可全部变成 0,而非零子集需要 \(|S|\) 次。于是状压预处理即可得到最少次数 \(cnt\)。
接下来分开考虑和为 0 和非 0 子集 \(S\) 的方案,首先 \(cnt!\) 可以最后再乘,先考虑和为 0 的情况,通过经验?我们可以把每次操作的两个点建一条边,于是最后会形成一棵树,任意定根,从叶子节点开始即可唯一还原出这个操作序列。注意实际上这棵树是无根的,于是方案数就是 \(|S|^{|S| - 2}\)。
对于和非 0 的情况,任意选择一个点变成当前和的相反数,就变成了和为 0 的情况,于是方案就是 \(2|S| \times S^{|S| - 2} = 2|S|^{|S| - 1}\)。
CF938E
问题在序列上是很经典的:预处理每个点包含它的最靠右的线段,然后倍增。
在树上,对于两个点 \((x,y)\) 而言,要么是直接跳到 \(lca\) 的两段次数之和,要么是存在一条经过 \(lca\),且经过 \(x,y\) 到 \(lca\) 的最近点的一个路线,设为直线 \((u,v)\),此时答案要减 1。而是否存在在两棵子树内的点可以看作在 \([L_u, R_u]\), \([L_v, R_v]\) 平面内是否存在 \((dfn_{st}, dfn_{ed})\) 一个点。
二维数点即可。 时间复杂度 \(O(n \log n)\)。
2022.11.3
CF487C
显然乘积问题转化成原根,当 \(n\) 不为质数时无解。问题就是 \([1, n - 1]\) 的一个排列,使得前缀和两两不等。
考虑和为 \(n\) 的两两配对,即:\(n - 1, 1, n - 3, 3, \dots\) 这样奇数位置构成了 \(n - 1, n - 2, \dots, \dfrac{n} 2\) 的排列,偶数位置构成了 \(1, 2, \dots, \dfrac n 2\) 的排列。
CF482D
没有翻转儿子是简单的,直接设 \(dp_{x, 0 / 1}\) 表示 \(x\) 子树内,选择了奇数 / 偶数个点的方案,\(O(1)\) 转移。
考虑加上翻转操作后,大多数方案都会 \(\times 2\),但存在特殊情况使得翻转前后答案相同:那就是子树大小全是偶数或者有偶数个奇数的方案,另外开两个数组保存即可。
CF425B
考虑观察合法矩形的特征:每一行要么和前一行相同,要么相反。
当 \(\min(n, m)\) 较小时,直接 \(2^n\) 枚举第一行的选择情况,然后用 bitset 贪心统计。
否则,至少存在一行 \ 一列在最优方案中未被翻转,枚举,再判断。
BS8197
仍然是先观察,三元组 \((x, y, z)\) 的两两距离最大值只可能是深度最大的点与其他点的距离。
枚举最大深度点 \(x\),于是只要 \(x\) 到两个点的距离都不超过 \(k\) 即为合法方案。将点按照深度排序后用点分树统计即可。
Bonus:\(k\) 固定,对所有的 \(c\) 元组 \(2 \leq c \leq n\) 统计答案。
法一:当 \(c\) 不固定时,上面的结论仍然成立,设 \(cnt_x\) 表示距离 \(x\) 不超过 \(k\) 的答案,于是有 \(ans_p = \sum\limits_{i = 1}^{n}\dbinom{cnt_i}{p - 1} = \dfrac{cnt_i!}{(p-1)!(cnt_i - p+1)!}\) ,卷积即可。
法二:考虑 “点数减边数”容斥,一个合法的 \(c\) 元组 \((x_1, x_2, \dots, x_c)\) 一定满足:所有距离 \(x_i\) 不超过 \(\dfrac{k}2\) 的点集的交集是一个联通块。考虑存在分数,于是把边拆成两条边。
对所有点和边分别计算出距离它不超过 \(k\) 的点(边要求距离最远点不超过 \(\dfrac k 2\)),然后点的贡献是 1,边的贡献是 -1,两次卷积。
LG6046 纯粹容器
首先根据 $E(X) = \sum\limits_{i = 0}^{\infty}P(X >i) $ 将期望转成计算 \(n\) 次的概率。将决斗的过程看做缩两个点。
对于单个点而言,找到在其左 / 右边第一个比 \(x\) 大的点 \(p_l, p_r\),则要求不能 \(p_l,p_r\) 和 \(x\) 缩在一起。考虑容斥,\(P(\overline{A \or B}) = 1 -P(A) - P(B) +P(A \and B)\),总方案显然是 \(\dbinom{n - 1}{t}\) ,\(P(A) = \dbinom{t}{x - p_l}(x - p_l)!(n - 1 - x+p_l)^{\underline{t - x +p_l}}\),\(P(A \and B) = \dbinom{t}{p_r - p_l}(p_r - p_l)!(n - 1 - p_r +p_l)^{t - x -p_r+p_l}\)
CF1299D
1 号点所连接的点只可能是 一个点的联通块 和 两个点的联通块。若选择保留两个点,则会多加入一个简单环。
不存在一条 1 的环异或为 0 相当于所有简单环构成了一个线性基。
观察到 \(\log_2 w = 5\),通过搜索发现,大小为 5 的线性基最多有 400 个。于是考虑直接把线性基加入 dp 状态里面:设 \(dp_S\) 表示目前 1 号点所在的连通块内线性基为 \(S\) 的方案。
先对所有与 1 相连的连通块计算出线性基,若已经存在异或为 0 的路径,则只能全部断开,否则可以将 1 号点线性基和当前线性基合并。通过预处理 \(400^2\) 对线性基的合并,时间复杂度 \(O(400^2 \times 5^2 +400n)\)。
CF804D
最长路径要么是两个连通块分别的直径,要么是两个不在同一个连通块的点到该连通块直径端点最大值,设为 \(dis_i\)。将 \(dis_i\) 排序后,启发式合并即可。
LG3412
设 \(f_x\) 表示 \(x\) 走到其父亲的期望长度,有 \(f_x = \dfrac{1}{deg_x}+\dfrac{1}{deg_x}\sum\limits_{y \in son_x}f_y+f_x+1\),发现\(f_x = deg_x+ \sum\limits_{y \in son_x}f_y\),于是直接考虑每个点作根节点的答案,计算出每条边的贡献。
LG7962
简单的推导可知:\(ans = (\sum\limits_{i}a_i)^2 -n(\sum\limits_ia_i^2)\)。并且题目所给的操作方式就是交换任意两个差分数组的值。
发现数据范围不大,直接模拟退火能得到 88 分的高分!
正解考虑差分数组的单谷性,答案的差分数组一定是先递减,再递增的,于是将差分数组排序后从小到大加入,这个值一定是放在首尾的。设 \(dp_s\) 表示当前和为 \(s\) 时最小的平方和, 注意到非零的 \(d\) 只有 \(\min(n,a )\) 个,\(O(na^2)\) 转移即可。
P3750 [六省联考 2017] 分手是祝愿
当 \(k = 0\) 时,由于低位不会对高位造成影响,直接从高到低贪心熄灭即可。 设执行次数为 \(cnt\)。
而令人惊讶的是,直接输出 \(cnt\) 有 80 分的高分!
当 \(cnt < k\) 时,直接输出 \(cnt\) 即可。 否则要计算出从 \(cnt\) 次到 \(k\) 次的期望操作次数。
注意到操作是线性无关的,这意味着一定是按照从高到低的顺序依次熄灭。设 \(dp_t\) 表示从还有 \(t\) 盏亮着的灯到 \(t - 1\) 盏的期望操作次数,转移:\(dp_t = \dfrac{t}{n} +\dfrac{n - t}{n}(1+dp_{t+1}+dp_t)\),即 \(dp_t = 1+\dfrac{n - t}{t}+\dfrac{n - t}tdp_{t+1}\),答案就是 \(\sum\limits_{i = k+1}^{cnt}dp_i\)。
CF605E Intergalaxy Trips
设 \(dp_i\) 表示 \(i\) 到 \(n\) 的最小期望天数,转移考虑枚举下一个点 \(j\),满足 \(dp_j < dp_i\),且对于 \(dp_k < dp_j\) 的 \(k\) 是关闭的,则 \(dp_i = \sum\limits_{dp_j < dp_i}p_{i,j}dp_j\prod\limits_{dp_k < dp_j}(1 - p_{i,k})+1\)
但上面计算的是与 \(i\) 相连的至少一条边开启的方案,还需要除以至少一条边开启的概率 \(P_i = 1 - \prod\limits_{dp_{k}}(1 - p_{i,k})\) 。
注意到 \(dp_i\) 只能由 \(dp_j <dp_i\) 的 \(j\) 转移,于是类似 dijkstra 的思想转移即可。
2022.11.4
[AGC030F] Permutation and Minimum
当 \(2n\) 个位置全是 -1 时,将其看做括号序列的模型:一个长度为 \(2n\) 的括号,其中下标代表相应的值,一个匹配的左右括号 \((x,y)\) 表示将 \(x,y\) 分在一组,不难发现答案为 \((\dbinom{2n}n - \dbinom{2n}{n - 1})n!\)
否则,匹配的两个位置有三种情况:都为 -1;一个为 1,一个为 -1;都不为 -1。
设都为 -1 的匹配有 \(cnt\) 个,最后答案乘上 \(cnt!\) 即可。
类似的思想,忽略掉都不为 -1 的位置,将不为 -1 的值看做方括号,为 -1 的看做圆括号,规定不能出现方方括号匹配的情况。设计 dp 状态为 \(dp_{i,j,k}\) 表示从 \(2n\) 从大到小考虑到 1,当前还有 \(j\) 个圆括号, \(k\) 个方括号。转移分类讨论当前值的出现情况:
- 若其是都不为 -1 的匹配,忽略。
- 若其未在原序列出现:
- 作为左圆括号,匹配一个右圆括号:\(dp_{i - 1, j - 1, k} \leftarrow dp_{i,j,k}\)
- 作为左圆括号,匹配一个右方括号:\(dp_{i - 1, j, k - 1} \leftarrow dp_{i,j,k} \times k\)
- 作为一个右圆括号:\(dp_{i - 1, j+1, k} \leftarrow dp_{i,j,k}\)
- 若其在原序列中出现过:
- 作为左方括号,匹配右圆括号:$dp_{i - 1, j - 1, k}\leftarrow dp_{i,j,k} $
- 作为右方括号:\(dp_{i - 1, j, k+1}\leftarrow dp_{i,j,k}\)
LG3991
平衡树维护 \(3 \times 3\) 的矩阵即可。
LG3343
证明一下提示中的结论:
\(n\) 个 \([0,1]\) 之间的随机变量 \(x_1, x_2, \dots, x_n\),其第 \(k\) 小的期望为 \(\dfrac{k}{n+1}\)。
先求出最大值的期望,对于一个确定的 \(x\),一个变量小于等于 \(x\) 的概率为 \(x\),从 \(n\) 个数中选出这个最大值的方案有 \(n\) 个,于是有:
同理 \(E(mn) = \dfrac{1}{n+1}\)。
第 \(k\) 大的方案就是:
根据分部积分法,设 \(u = \dfrac{x^{k+1}}{k+1}, v = (1 - x)^{n - k}\),其等于:
因为 \((uv)|_0^1 = 0\),于是答案等于
设
则有 \(a_k = a_{k+1} \times \dfrac{n - k}{k+1}\)。
又因为 \(a_n = \dfrac{n}{n+1}\),故 \(a_k = \dfrac{i!(n - i)!}{(n+1)!}\),因此期望为 \(a_k \times n \times \dfrac{n - 1}{k - 1} = \dfrac{k}{n+1}\)。
拓展:\(\Gamma\) 函数和 \(\Beta\) 函数:
有结论:
- \(\Gamma(1) = 1\) 且 $\Gamma(x+1) = x\Gamma(x) $,即 \(\Gamma(x) = (x - 1)!\)。
- \(\Beta(x,y) = \dfrac{\Gamma(x)\Gamma(y)}{\Gamma(x+y)}\)。
有了结论之后就很简单了,设 \(dp_{S,i}\) 表示当前已经使得点集 \(S\) 联通,且已经连了 \(i\) 条边的方案,答案就是 \(\dfrac{1}{m+1}\sum\limits_{i = 0}^{m} \dfrac{\binom{m}{i} - dp_{all,i}}{\binom{m}i}\) ,转移 \(dp_{S,i} = \dbinom{cnt_S}2 - \sum\limits_{j \leq i} \sum\limits_{T \subset S}dp_{T,j} \dbinom{cnt_{S /T}}{i- j}\)
LG3239
设 \(f_{i,j}\) 表示考虑到前 \(i\) 张卡牌,已经打出 \(j\) 张的概率,则 \(f_{i,j} = f_{i - 1, j - 1}(1 - (1 - p_i)^{k - j+1})+f_{i - 1, j}(1-p_i)^{k - j}\)
答案就是 \(\sum\limits_{i}d_i\sum\limits_{j}f_{i - 1, j}(1 - (1 - p)^{k - j})\)
LG3352
考虑 \(E(a_i) = \max a_i - \sum\limits_{j}P(j >a_i)\),于是需要计算权值小于 \(j\) 的方案。
枚举 \(v\),将 \(< v\) 的值设为 \(0\),\(\geq v\) 的值设为 1,每次操作可以看做把全 0 连续段缩一部分,设 \(dp_{k,l,r}\) 表示经过 \(k\) 次操作后,满足 \(a_l = a_r = 1, \forall i \in(l,r),a_i = 0\) 的方案。
转移有考虑该次操作是否包含区间,有 \(dp_{k,i,j} \leftarrow dp_{k - 1, i,j} \times(\dfrac{i(i+1)}2 +\dfrac{(n - j+1)(n - j +2)}{2}+\dfrac{(j - i)(j - i - 1)}{2})+\sum\limits_{l < i}dp_{k - 1, l,j}\times l+\sum\limits_{r>j}dp_{k - 1, i,r}\times(n -r+1)\) 可以前缀和优化为 \(O(n^3)\)。每次枚举 \(v\),将初始相邻为 1 的位置 dp 初始化,时间复杂度 \(O(n^4)\)。
发现每次 dp 转移都是一样的,只有初始值有变化,于是预先把所有的 dp 累加后再做一次 dp 即可。
答案即是 \(\sum\limits_{l = 0}^{n+1}\sum\limits_{r = l+2}^{n}\sum\limits_{k = l+1}^{r - 1}dp_{m,l,r}\)。
LG1758
考虑 \(\sum a_i^2\) 的组合意义:选两次,两次方案均相同的方案。
于是设 \(dp_{i,j,k}\) 表示第一次选球,在上管道选了前 \(i\) 个,在下管道选了前 \(j\) 个;第二次在上面选了 \(k\) 个,下面选了 \(i+j - k\) 的方案。转移显然。
[AGC013E] Placing Squares
首先有暴力 dp :\(dp_i = \sum\limits_{j < i\and!vis_j}dp_j(i - j+1)^2\)。发现是两次的,不能直接优化。
考虑把这个问题转化成神必组合意义:在长度为 \(n\) 的序列中插入若干个隔板,一些特定的位置不能插隔板,然后需要在每个相邻的隔板中选出一个白球,一个黑球(可以重合)的方案。
设 \(dp_{i,0 / 1/ 2}\) 表示当前考虑到前 \(i\) 个位置,当前 \(i\) 所在连通块选择了 0 / 1 / 2 个球的方案,转移分当前位置是否被限制:
- 若当前位置未被限制,则有:
- \(dp_{i+1,0} \leftarrow dp_{i,0}+dp_{i,2}\)
- \(dp_{i+1,1} \leftarrow dp_{i,1}+2dp_{i,0}+2dp_{i,2}\)
- \(dp_{i+1,2}\leftarrow 2dp_{i,2}+dp_{i,0}+dp_{i,1}\)
- 若当前位置被限制,则有:
- \(dp_{i+1, 0} \leftarrow dp_{i,0}\)
- \(dp_{i+1,1} \leftarrow dp_{i,1}+2dp_{i,0}\)
- \(dp_{i+1,2} \leftarrow dp_{i,2}+dp_{i,1}\)
矩阵快速幂即可。
CF913F
竞赛图缩点后会形成一条链,考虑枚举这条链的末尾。
设 \(dp_n\) 表示 \(n\) 个人的期望值,则有:\(dp_n = \sum\limits_{i = 1}^{n}c_id_{n,i}(dp_i+dp_{n - i}+\dbinom i 2+\dbinom {n - i}2)\),即 \(dp_n = \dfrac{\sum\limits_{i = 1}^{n - 1}c_id_{n,i}(dp_i+dp_{n - i}+\dbinom i 2 +\dbinom {n - i}2)+c_nd_{n,n}\dbinom n 2}{1 - c_nd_{n,n}}\)
其中· \(d_{n,i}\) 表示从 \(n\) 个点中选出 \(i\) 个出度为 0 的点概率,\(c_i\) 表示 \(i\) 个点组成强联通分量的概率 。
\(d\) 的转移是简单的,只用枚举 \(n\) 号点的连通情况:\(d_{n, i} = d_{n - 1, i - 1} \times p^{n - i}+dp_{n - 1, i} \times (1 - p)^i\)。
\(c\) 的转移同理:\(c_i = 1 - \sum\limits_{j < i}c_jd_{i,j}\)。
\(O(n^2)\)。
CF1067D
由于 \(a_i < b_i\),最优策略一定是成功一次后,一直选择 \(p_ib_i\) 最大的,设 \(w = \max p_ib_i\),则考虑第一次成功之前的期望:设 \(dp_n\) 表示剩下 \(n\) 秒的期望收益,则有:\(dp_n = \max \limits_{i} (p_i \times (a_i+(n - 1)*w)+(1 - p_i)dp_{n - 1})\)。
发现有乘积项,套路地拆成斜率式的形式:\(dp_t = p_i((n - 1) \times w - dp_{t - 1})+p_ia_i+ dp_{t - 1}\)
于是可以看作 斜率为 \(dp_{t - 1} - (n - 1) \times w\) 的直线截点 \((p_I, p_ia_i)\)。 于是先建一个上凸包。每次直接二分可以做到 \(O(m\log n)\)
但由于 \(m\) 太大,我们猜测 \(g_t = dp_{t} - t \times w\) 随着 \(t\) 的增大单调不增,这样每个在凸包上的点对 dp 的转移就是一段区间。
由于 \(g_t - g_{t - 1} = dp_t - dp_{t - 1} - w\),每次的收益一定比不会大于 \(w\),于是单调性得证。
于是直接对每个点扫一遍,考虑固定一个 \(i\) 时 \(g_t\) 的变化:\(g_t = g_{t - 1} - p_ig_{t - 1} - w\),也是一个一次函数,于是直接倍增预处理一下函数的复合,再从大往小 check 即可。 时间复杂度 \(O(n \log n)\)。
CF986E
一开始想复杂了,以为 gcd 要用莫反来搞,但其实是乘积,对于每个素因子分开考虑就好。
将询问差分后,设 \(V = p_1^{\alpha_1}p_2^{\alpha_2}\dots\),变成询问树上一段前缀中出现次数为 \(cnt\) 的个数,贡献为 \(p_k^{\min(cnt, \alpha_k)}\)。由于 \(\alpha_i, cnt \leq 23\),直接开个桶就好了,对于每个素因子 \(O(\log_PV)\) 算一下就好了。
CF1605F
先考虑一个固定的序列是否是好的:显然,记录当前 \(\mathrm or\) 前缀和 \(S\),每次选择两个 \(x, y\) 满足 \(x | S = y |S\),拼在首尾,再更新 \(S\)。
发现这个构造并不能直接对好序列计数,但是可以考虑利用这个操作搭建起好序列和坏序列的桥梁,然后通过容斥计算好序列。
一个坏序列一定存在一个极长的好序列,满足剩下的未被加入的数在除去 \(S\) 中为 1 位后两两不同,且非 0。
但有一些细节:当一个好序列长度为奇数,且中间的数出现了前面没有出现过的二进制,这个序列不会映射到任何一个好序列。于是不能称这个序列是好的。
设 \(h_{n, m}\) 表示 \(n\) 个数,其二进制的并的大小恰好为 \(m\) 的方案,其可以简单二项式反演得到:\(h_{n, m} = \sum\limits_{i \leq m}(-1)^{m - i}\dbinom{m}i(2^{i})^n\),设 \(f_{n, m}\) 表示合法的长度为 \(n\) 的值为 \(m\) 的序列个数, \(g_{n,m}\) 为非法个数,则根据上面的过程,枚举极长的合法序列和合法序列的二进制并的大小,有:\(g_{n, m} = \sum\limits_{i < n}\sum\limits_{j < m}\dbinom{n}i\dbinom m jf_{i,j}(2^{j})^{n - i} r_{n - i, m - j}\) ,其中 \(r_{i,j}\) 表示长度为 \(i\) 的序列,值在 \([1,2^j)\) 且两两不同,并为全集的方案。同样可以二项式反演得到。
然后 \(f_{n, m} = all_{n, m} - g_{n,m}\),答案就是 \(\sum\limits_{i}f_{n,i}\dbinom m i\)。 如果当 \(n\) 是奇数,还需要而外加上长度为 \(n - 1\) 的合法序列的数量。
P4707 重返现世
题目即求 \(E(\mathrm{kthmax}(S))\),发现 \(k \geq n - 10\), 先令 \(k \leftarrow n - k\) 变成求第 \(k\) 小的。根据 \(\min - \max\) 容斥的扩展形式,有:
\(E(\mathrm{kthmin}(S)) = \sum\limits_{\emptyset \subset T \subseteq S}(-1)^{|T| - 1} \dbinom{|T| - 1}{k - 1}E(\max(T))\)。而对于一个固定的 \(T\),\(E(\max(T)) = \dfrac{m}{\sum\limits_{x \in T}p_x}\)。
发现 \(m \leq 10000\),于是考虑直接把 \(\sum p\) 记到 dp 里面:设 \(dp_{i, j, s}\) 表示当前考虑到前 \(i\) 个数,目前的 \(k = j\), \(\sum\limits_x p_x = s\) 的容斥系数之和,答案就是 \(\sum\limits_{i} dp_{n, k, i} \times \dfrac{m} i\)。
考虑转移,不选择 \(i\) 就是 \(dp_{i - 1, j, s}\), 否则根据 \(\dbinom{|T| - 1+1}{k - 1} = \dbinom{|T| - 1}{k - 1}+\dbinom{|T| - 1}{k - 2}\),于是 \(dp_{i, j, s} \leftarrow dp_{i - 1, j, s}+dp_{i - 1, j - 1, s - p_i} - dp_{i -1, j, s - p_i}\)。
CF1515E Phoenix and Computers
最后呈现的形式一定是若干个间隔为 1 的连续段, 设其 EGF 为 \(F(x)\),答案就是 \(\sum\limits_{k} [x^{n - k + 1}]F^k\)。
对于单个连续段而言,其方案数为 \(2^{i - 1}\),意思是随便选择一个当作第一个开的,每次可以选择左边或者右边。
然后直接卷起来即可,时间复杂度 \(O(n^3)\)。
P5279 [ZJOI2019]麻将
能胡牌当且当存在 7 个对子或者 4 个面子 + 1 个对子。
考虑从小到大加入牌,只保留未胡牌的状态,考虑设计 \(dp_{0 / 1,j, k}\) 表示当前是否存在雀头, 有 \(j\) 个形如 \([i - 2, i - 1]\) 的对子, \(k\) 个 \(i - 1\) 时,已经存在的最多的面子个数。注意到 \(j \geq 3\) 时能直接组成 2 个刻子, \(k \geq 3\) 时能直接组成 1 个刻子,因此 \(j, k < 3\)。
每次考虑加入 \(cnt\) 张 \(i\)。 那么会优先拼 \([i - 2, i - 1, i]\), 然后拼 \([i - 1, i]\),最后若剩下 \(\geq 3\) 个直接拼成 \(i, i , i\)。
于是可以像矩阵那样保存答案。 同时,若 \(cnt \geq 2\),还可以先用 2 张 \(i\) 组成雀头后更新 \(dp_1\)。
对于 7 个对子的情况,直接同一个变量表示当前对子的数量 。然后用 dp of dp 转移,bfs 一下状态个数不多。
然后设 \(dp_{i, u}\) 表示目前已经抽了 \(i\) 张牌,当前在自动机上的 \(u\) 点的方案,可以 \(O(2092 \times n \times 4n)\) 转移。
最后答案就是 \(\dfrac{1}{(4n - 13)!}\sum\limits_{i}\sum\limits_u dp_{i, u} \times i !\times (4n - 13 - i)!\)。
P5406 [THUPC2019]找树
P7468 [NOI Online 2021 提高组] 愤怒的小 N
一年前..折戟成沙..今天..30min内...我不再是以前那个我了
把 a 看做 0, b 看做 1。后 \(2^{n - 1}\) 的序列是由前 \(2^{n - 1}\) 在最高位,的容易发现该序列的通项
BS8240
对于一条边连向的两个点,我们只关心他们颜色相同与否。于是可以考虑把 \(n\) 个点分成若干集合,每个集合内部颜色相同,集合之间没有区别。不难发现这就是贝尔数的定义。
注意到 \(bell_{12} = 4213597\),于是当 \(n \leq 12\) 时直接搜索 \(n\) 个点的划分,再乘上 \(k^{\underline{cnt}}\) 即可。
再考虑一棵树的情况,容易设计 $dp_{x,i} $ 表示 \(x\) 颜色为 \(i\) 的总权值然后 \(O(nk)\) 转移,由于颜色之间没有区别,每个 \(i\) 的 \(dp_{x,i}\) 都是一样的,所以可以 \(O(n)\)。
于是就 70 了。
再考虑最后几个点,发现非树边最多只有 \(10\) 条,类似上面的思路,随便找一棵生成树后,对于每条非树边,直接搜索确定一点的颜色,此时设 \(dp_{x,i}\) 表示选择第 \(i\) 种颜色的方案(当 \(i = 0\) 时是未选择的 \(k - cnt\) 种颜色),最后把根据当前点的颜色选择,将其所对应的非树边答案累加。
于是复杂度就是 \(O(bell_{10}nk)\),因为 \(bell_{10}\) 是 1e5 级别,算出来只有 1e8,但会被卡常。
题解的一个解决方案是将 1 度点删去,2 度点将其贡献累加到所连向的两个点。这样每个点度数 \(\geq 3\),于是总点数减少,跑得飞快。
BS8241
建出括号树,对于一个询问 \(x, y(x<y)\) 而言,一定是不断跳,跳到其 lca 的两个儿子,要么直接从 lca 处转换括号,要么从同层括号之间单向移动。
于是只用预处理一个左 / 右括号到其父亲的 左 / 右括号的最小步数,显然可以在建树时用一个 \(2 \times 2\) 的矩阵表示转移。然后大力分讨就 over 了。
还有小清新的直接倍增写法,就是直接对每个点预处理跳 \(2^j\) 能到达的最左 / 最右点,一个跳 $2^j $ 的能到达的最左点要么是最靠左的 \(2^{j - 1}\),要么是最靠右的 \(2^{j - 1}\)。询问类似上面的做法,从两个点开始跳,一直跳到 lca 即可。
BS8236
硬核推柿子题。
首先考虑求出一个点的期望深度,设 \(d_x\) 表示 \(x\) 的期望深度,\(b_x\) 为 \(a_x\) 的前缀和,有转移 \(d_x =\dfrac{\sum\limits_{i = 1}^{x - 1}a_i(d_i+c_i+c_x)}{b_{x - 1}}\),可以通过分离变量做到 \(O(n)\)。
对于询问 \(x,y\),我们想要对于每个 \(l \in [1, x]\),计算出 \(l\) 为 \(x,y\) 的 \(\mathrm{lca}\) 的概率,答案就是 \(d_x+d_y -2\sum\limits_{l}P_ld_l\)。
假设 \(x<y\),直接枚举 \(x - y\) 的路径上经过的点集 \(S_{x,y}\),会发现其由两部分组成:在 \((l,x)\) 上的点可以在 \(l - x\) 的路径上,也可以在 \(l - y\) 上;对于 \((x,y)\) 的点,只能在 \(l - y\) 上,然后 开 幕 雷 击:
\(P_l =\dfrac{a_l^2}{b_{x - 1}b_{y - 1}} \sum\limits_{S_1 \subseteq (l, x)}\sum\limits_{S_2\subseteq (x,y)} \prod\limits_{i \in S_1}\dfrac{2a_i}{b_{i - 1}}\prod\limits_{i \in S_2} \dfrac{a_i}{b_{i - 1}}\)
解释一下:本质上就是一堆点,其 \(\dfrac{a_{p_{i - 1}}}{b_{p_i - 1}}\) 的乘积,只不过把 \(l, x, y\) 的贡献单独处理了,这个柿子在 \(x = l\) 时不成立,需要特殊处理。
然后将 \(\sum\limits_{S_1 \subseteq (l,x)}\prod ...\) 看成每个点选或不选:\(\prod\limits_{i = l+1}^{x - 1}(1+\dfrac{2a_i}{b_{i - 1}}) = \prod\limits_{i = l+1}^{x - 1}\dfrac{a_i+b_{i}}{b_{i-1}}\),右边 \(\prod\limits_{i = x+1}^{y - 1}\dfrac{b_i}{b_{i - 1}} = \dfrac{b_{y - 1}}{b_x}\)。
最后的答案就是 \(d_x+d_y - 2\sum\limits_{l = 1}^{x}d_l \times \dfrac{a_l^2}{b_xb_{x - 1}}\prod\limits_{i = l+1}^{x - 1}\dfrac{a_i+b_{i - 1}}{b_{i - 1}}\)。预处理 \(\dfrac{a_i+b_{i - 1}}{b_{i - 1}}\) 的前缀积即可。
BS8237
题意就是划分成两个公差相同的等差数列(可以有一个为空),直观感受一下,这个公差不会太大。
为了方便确定公差的范围,我们不妨将公差 \(d\) 的上界和下界写出来,并枚举首项 \(b\):
最少的操作次数 \(mn = \dfrac{\frac{n(n-1)}{2}d+bn - \sum a_i}{2}\),\(mx = \dfrac{a_{mx} \times n - \sum a_i}{2}+2n\),由于 \(mn \leq mx\),最后发现 \(nd \leq 1e6\)。
这意味着我们可以直接暴力枚举 \(d \in [-\dfrac{lim}n, \dfrac {lim}n]\),然后再花 \(O(n) - O(n \log n)\) 的时间得到让一段前缀 / 后缀变成公差为 \(d\) 的等差数列的答案,然后用 \(pre\) 和 \(suf\) 拼起来。
设 \(c_i = a_i - (i - 1) \times d\),那么对于一个首项 \(b\),对于 \(c_i - b \leq 0\) 的贡献而言,若 \(b - c_i\) 为偶数,就可以一直进行 +2 操作,次数就是 \(\dfrac{b - c_i}2\),否则需要加到 1 后减去 1,贡献就是 \(\dfrac{b+3 - c_i}{2}\);对于 \(c_i - b > 0\) 的贡献就是 \(c_i - b\)。
注意到这类似带权中位数问题,对于 \(c_i \leq b\),贡献可近似看做 \(\dfrac{b - c_i}2\),\(c_i > b\) 就是 \(c_i - b\)。根据数学??积累可知:\(b\) 取 \(c[n - \left\lceil \frac n 3\right\rceil+1]\) 取到,由于奇偶性的问题,还需要代入该值 -1 检验。
考虑动态维护这个过程,我们需要动态维护前 \(n - \left\lceil \frac n 3\right\rceil+1\) 的奇 / 偶个数以及和,后 \(\left\lceil \frac n 3\right\rceil\) 的个数以及和就可以 \(O(1)\) 计算答案了。
用对顶堆时刻维护该过程,时间复杂度 \(O(nd \log n)\)。
2023.1.12
CF1392H ZS Shuffles Cards
首先需要读懂题意,每次重新抽牌时 \(S\) 是不会变的,且 joker 不会被抽走。
考虑 dp,设 \(dp_{i, j}\) 表示当前卡牌中有 \(i\) 张牌,\(|S| = j\) 的方案数。每种卡牌可以分为三类:只在牌堆中出现的 \(n - j\) 张;只在 \(S\) 中出现的 \(n - i\) 张;在牌堆和集合都出现的 \(i+j - n\) 张的期望抽卡次数。
转移显然:\(dp_{i,j} = 1+\dfrac{n -j}{i+m}dp_{i-1, j+1}+\dfrac{i+j-n}{i+m}dp_{i-1,j}+\dfrac{m}{i+m}dp_{n, j}\)。
答案是 \(dp_{n, 0}\)。
\(dp_{i,n}\) 特殊转移,有 \(dp_{i,n} = 1+\dfrac{i}{i+m}dp_{i - 1, n}\)。
不能直接转移,高斯消元复杂度太高,考虑将每个数 \(dp_{i, j}\) 写成关于 \(dp_{n, j}\) 的一次函数或许可以 \(O(n^2)\),但无法优化。
参考鱼大的思路,先换元 \(a = n - j, b = i+j - n\),变为 \(dp_{a,b} = 1+\dfrac{a}{a+b+m}dp_{a-1,b}+\dfrac{b}{a+b+m}dp_{a, b - 1}+\dfrac{m}{a+b+m}dp_{a, n-a}\),答案还是 \(dp_{n,0}\)。好处是转移只改变了一个项
当 \(a = 0\) 时:\(dp_{0, b} = 1 + \dfrac{b}{b+m}dp_{0, b - 1}\),解得 \(dp_{0, b} = \dfrac{m+1+b}{m+1}\)。
然后考虑第一个柿子,代入 \(b +1\) 得:\(dp_{a, b+1} = 1 +\dfrac{a}{a+b+1+m}dp_{a-1, b+1} +\dfrac{b+1}{a+b+1+m}dp_{a, b }+\dfrac{m}{a+b+1+m}dp_{a, n - a }\)。
消去 \(dp_{a, n - a}\) :将柿子写成关于 \(dp_{a, b} - dp_{a, b - 1}\) 的形式,也恰好能完全凑成:\((a+b+m+1)(dp_{a,b+1}-dp_{a,b}) = 1+b(dp_{a,b} - dp_{a, b - 1})+a(dp_{a - 1, b+1} - dp_{a - 1, b})\)。
特别地,当 \(b = 0\) 时,有 \((a+m+1)(dp_{a, 1} - dp_{a, 0}) = 1+a(dp_{a - 1, 1} - dp_{a - 1, 0})\)。
猜测 \(dp_{a, b} - dp_{a, b - 1}\) 是一个常数 \(\dfrac{1}{m+1}\),因为当 \(a = 0\) 时成立,代入 \(a = 1, b = 0\) 时也成立,然后即可数学归纳法证明(当然,你可以打表)
再代入 \(dp_{a, b} - dp_{a, b - 1} = \dfrac{1}{m+1}\) 可得 \(dp_{a, b} - dp_{a-1, b + 1}= \dfrac{m(n+m+1)}{a(m+1)}\)。
因此 \(dp_{n, 0} = \sum\limits_{a = 1}^n\dfrac{m(n+m+1)}{a(m+1)}+dp_{0, n } = \dfrac{(n+m+1)(1+mH_n)}{m+1}\),其中 \(H_n\) 是调和级数。
当然,还可以利用期望的线性性同样得到上面的柿子。
[NOI2020] 制作菜品
首先,当 \(m \geq n - 1\) 必然有解。一个简单的构造为取出最大值 \(mx\) 和最小值 \(mn\),若 \(mn \geq k\) 则说明 \(m \geq n\),此时直接用 \(mn\) 制作;否则必然有 \(mn+mx \geq k\)(等号只在 \(m = 1, n = 2\) 时取到 ),用反证法可简单证明,因此用一个最大和最小得到 \((m - 1, n - 1))\) 的子问题。随便输出一下方案就行了。
当 \(m = n - 2\) 时,猜测若 \(d_i\) 能分成两个 \(m = n - 1\) 集合时一定有解,充分性显然。必要性只用当 \(m = 1, n = 3\) 显然无解即可证明,于是直接将 \(d_i - k\) 做 01 背包即可,用 bitset 优化,时间复杂度 \(O(\dfrac{n^2k}{w})\),但是跑的很快。
CF566C Logistical Questions
只考虑一条边的两个端点 \(u, v\),设其最优带权重心距离 \(u\) 为 \(x\),则代价为 \(a_ux^{1.5}+a_v(l - x)^{1.5}\),求导为 \(1.5a_u\sqrt x-1.5a_v\sqrt{l - x}\) 为凸函数,当导数小于 0 时将 \(x\) 增大,否则减小即可。
拓展到多个点也是相同的,由于凸函数之和仍然是凸函数,重心唯一。设当前在 \(u\),\(u\) 到 \(i\) 的距离为 \(d_i\),则从 \(u\) 走到 \(v\) 的代价为 \(f(v) = \sum_{i \in sub_v}a_i(d_i - x)^{1.5}+\sum_{i\neq sub_v}a_i(d_i+x)^{1.5}\),求导为 \(f'(v) = 1.5\sum\limits_{i \neq sub_v}a_i\sqrt{d_i+x} - 1.5\sum\limits_{i\neq sub_v}a_i\sqrt{d_i - x}\) ,只用代入 \(x = 0\) 观察 \(f'(v)\) 是否 \(< 0\) 就进入 \(v\)。
用点分治来逐步逼近,每次只用暴力算出 \(f(v)\) 和总答案,由于总计算次数为 \(O(\log n)\) 级别,因此时间复杂度 \(O(n\log n)\)。
CF698F Coprime Permutation
有点怪,明天再补。
[JSOI2019]神经网络
最终哈密顿回路的形态是从 1 号树开始出发,每次在一棵树上走一条链切换到另一棵树上,最后把所有树覆盖完。
单独考虑每一棵树,其实就是把它分成若干条链的方案,每个长度 \(>1\) 的链方案数为 2,设 \(dp_{i, j, 0 / 1 / 2}\) 表示 \(i\) 子树内有 \(j\) 条链,且 \(i\) 的度数为 \(0 / 1/ 2\) 的方案。为了方便处理 \(l = 1\) 的情况,初始化 \(dp_{i, 0, 0} = 1, dp_{i, 1, 2} = \dfrac 1 2\),最后划分成 \(i\) 条链的方案就是 \((dp_{1, i, 1}+dp_{1, i, 2})\times 2^i\)。dp 转移只用考虑 \((u, v)\) 这条边加不加然后做背包。
然后考虑把几棵树的路径拼起来,但是必须要求相邻两条路径不能来自同一棵子树,否则会算重。直接容斥,将一棵树 \(i\) 条链合并成 \(j\) 条,容斥系数为 \((-1)^{i - j}\),方案为将 \(i\) 个有标号小球放进 \(j\) 个无标号盒子的方案,为 \(\dbinom{i - 1}{j - 1}\times \dfrac{i!}{j!}\)。最后把每棵树的答案卷起来就是总的选 \(i\) 条链的方案。最后每个长度 \(i\) 乘上圆排列方案 \((i - 1)!\) 相加。
[省选联考 2020 A 卷] 魔法商店
对每个 \(a_i\) 考虑 \(a_i\) 能被哪些数替代建出偏序关系。先在线性基中加入除了 \(a_i\) 的所有在 \(A\) 集合中的元素,然后依次判断 \(c_i\) 是否能再次插入,如果能则连边。对于 \(b_i\) 同理。
然后套 \(L_2\) 问题保序回归板子。流程是先整体二分,计算 \(f_i \in [l, r] /(mid, mid+\epsilon )\) 的答案,每个点只会取到 \(mid\) 或者 \(mid+e\),求导后算最小权闭合子图,再分治即可。
由于要求 \(f_i\) 为整数,当 \(r - l = 1\) 时就可以直接算 \(f_i = l\) 或 \(r\) 的答案。
时间复杂度大概为 \(O(\log \max v_i \times \mathrm{maxflow}(n, nm))\)。
2023.1.13
[NOI2019] 机器人
简单 DP:设 \(dp_{l, r, k}\) 表示区间 \([l, r]\) 最大值不超过 \(k\) 的合法放置的方案数,转移只需要枚举最靠右的最大值,则该位置放机器人能走完整个序列,且任何其他位置不能到达,\(dp_{l, r, k} = dp_{l, r, k - 1}+\sum\limits_{A_p \leq i \leq B_p}dp_{l, p - 1, k} \times dp_{p+1, r, k - 1}\) 。由于要求绝对值差 \(\leq 2\),因此合法的位置是 \(O(1)\) 级别。 时间复杂度 \(O(n^2k)\) 。
由于合法区间必然不多(打表可发现当 \(n = 300\) 时只有 \(2400\) 个不到),采取记忆化搜索,复杂度 \(O(2400k)\)。
当所有 \(A_p = 1, B_p = 10^9\) 时,所有的转移都是一样的,且 \(dp_{l, l}\) 是关于 \(k\) 的一次函数,$dp_{l, l+1} $ 可以由 \(dp_{l, l},dp_{l+1, l+1}\) 得到,因此是一个二次函数。不难归纳,\(dp_{l, r}\) 是关于 \(k\) 的 \(r - l+1\) 次多项式,因此只需要把前 \(n+1\) 个 dp 值算出来,然 后线性插值即可。
当 \(A_p\),\(B_p\) 不同时,先将区间左闭右开离散化,则算 \([l, r)\) 区间的 \(dp_{1, n}\) 时只需要得知 \(dp_{L, R, l - 1}\) 的 dp 值,如果我们从小到大处理区间的话,这是个常数。剩下的和 \([l, r)\) 在一段区间仍然可以插值。算完后再把当前的 \(r - 1\) 处的 dp 值插出来,赋值到下一轮的 \(dp_{l, r, 0}\)。
[ZJOI2019]线段树
考虑一次修改 \([l,r]\) 会对线段树上的节点标记的影响,可将线段树节点分为以下 5 大类(图源来自 Sooke,侵删歉):
设 \(f_{u,i}\) 表示经过 \(i\) 次分裂后,线段树 \(u\) 号节点的标记个数。
- 对于一类点,标记清空,\(f_{u,i - 1}\)。
- 二类点,一定有标记,\(f_{u,i- 1}+2^{i - 1}\)。
- 三类点,当且仅当 \(u\) 到根上的任意一点有标记时,它会得到标记,因此设 \(g_u\) 表示 \(u\) 到根都没有标记的方案,\(f_{u, i - 1}+2^{i - 1} - g_u\)。一类点:\(g_u \leftarrow g_u+2^{i - 1}\),二类点:\(g_u\)。
- 四类点:不改变当前状态,因此 \(f_{u, i - 1} \times 2, g_{u}\)。
- 五类点:都不改变,\(f_{u, i - 1} \times 2, g_u \times 2\)。
遍历能遍历到 1,2,3 类节点,直接暴力更新即可。对于 4,5 类节点,都是乘法操作,因此线段树维护 2 两个乘法 tag 和当前 f, g 和 \(f_u\) 总和。
CF506E Mr. Kitayuta's Gift
由于统计不同的串的方案,于是直接从答案回文串的形态入手。答案串从左右往中间每次添加两个相同字符(\(|s|+n\) 为奇数且最后一次填除外)得到,而给定串 \(s\) 若是它的子序列则可以统计进答案。根据上面的过程,假设 \(|s|+n\) 为偶数,不难设计出一个区间匹配的 dp:
设 \(dp_{l, r, k}\) 表示已经往左右加入 \(k\) 对字符,\(s\) 与这 \(k\) 对字符尽量匹配后还有 \([l, r]\) 为匹配的方案(匹配必然是从左右往中间的)。
- 若 \(l > r\) 表明匹配完毕,因此随便加即可, \(dp_{l, r, k+1}\leftarrow d_{l, r, k} \times 26\)。
- 若 \(l \leq r\),\(s[l] = s[r]\),有 \(25\) 种方案不能匹配,\(1\) 种方案匹配,\(dp_{l, r, k+1} \leftarrow dp_{l, r, k}\times 25\),\(dp_{l +1, r - 1, k+1}\leftarrow dp_{l, r, k}\)。
- 若 \(l \leq r, s[l] \neq s[r]\),有 \(24\) 种方案左右都不匹配,一种方案匹配 \(l\),一种匹配 \(r\),\(dp_{l, r, k+1} \leftarrow dp_{l, r, k}\times 24,dp_{l+1,r,k} \leftarrow dp_{l, r, k}, dp_{l,r -1, k+1}\leftarrow dp_{l, r, k}\)。
设 \(|s| = m\),\(k = \dfrac{m+n}{2}\)直接算 $ O(nm^2)$。强行将 \([l, r]\) 看成二维向量矩乘 $O(m^6 \log n) $,显然太劣。
将 \([l, r]\) 看做一个状态,状态的转移看做 DAG 上的连边,发现很多转移都是在走自环,设自环方案为 24 的为 24 点,25 的为 25 点,建出如下 DAG:
若一个从起点到终点的路径上有 \(a\) 个 24 点,则必有 \(b= \left\lceil\dfrac {m - a}2\right\rceil\) 个 25 点。对于具有相同 24,25 点的路径,其在转移之间插入自环的方案数相同(可以看做 \(a +b\) 个非负变量和为 \(k\) 的方案,变量之间显然是没有区别的)。只需计算出 \(a\) 个 24 点的方案和在 \(a\) 个 24 点,\(b\) 个 25 点中插入自环的方案相乘即可。
计算 \(a\) 个 24 点的方案:直接设 \(dp_{l, r, k}\) 表示当前在状态 \([l, r]\),已经经过 \(k\) 个 24 点的路径条数,记忆化搜索即可。时间复杂度 \(O(m^3)\)
计算 \(a\) 个 24 点,\(b\) 个 25 点的方案:可建立新的一张 DAG 连成一条链,\(s\) 向第一个 24 点连边,第 \(i(i < a)\) 个 24 点向 \(i+1\) 个 24 点连边,第 \(a\) 个 24 点向第一个 \(25\) 点连边,然后跑矩快。本质不同的 \(a\) 有 \(O(m)\) 个,时间复杂度 \(O(m^4\log n)\)。 不优秀。
问题在于我们没有利用矩快可以求出任意两点之间的长度为 \(k\) 的路径条数,考虑直接把这 \(O(m)\) 个路径整合到一起,如下图:
红点为 \(m - 1\) 个 24 点,绿点为 \(\left\lceil\dfrac m 2\right\rceil\) 个 25 点,每个 25 点连向终点 “26” 点。这样的话算整个的矩快,若要计算有 \(a\) 个 24 点的方案,只需要提取倒数第 \(a\) 个红点到第 \(\left\lceil\dfrac{m - a} 2\right\rceil\) 个绿点之间的路径条数即可,时间复杂度 \(O(m^3\log n)\)。
还有一个问题:当 \(n+m\) 为偶数时,最后一次只能添加一个字符,只需要钦定最后一次选择的是 24 点,然后再容斥一下即可。
2023.1.14
P4727 [HNOI2009]图的同构计数
考虑 Burside 引理:\(|X(G)| = \dfrac{1}{|G|}\sum\limits_{g \in G}|X^g|\)。将每条边看做有 \(0\) 或 1 的颜色,则 \(|X| = 2^{\frac {n(n - 1)}2}\),\(|G|\) 为全体置换 \(n!\)。
先考虑置换的所有轮换,设其大小为 \(k\)。
考虑两个端点都在其内部的方案,问题相当于一个 \(k\) 个点的完全图的等价类个数,每个长度为 \(i(i \leq \dfrac k 2)\) 的边都会形成一个等价类,因此贡献为 \(2^{\frac k 2}\)。
考虑一条边的端点不在同一个轮换的情况,设两个轮换的大小为 \(s1, s2\),此时随着两个轮换的进行,会在 \(\mathrm{lcm}(s_1,s_2)\) 后回到原点,因此会有 \(\dfrac{s1 \times s2}{\mathrm{lcm}(s_1,s_2)} = \gcd(s_1, s_2)\) 个等价类,每个等价类的贡献同样为 \(2^{cnt}\)。
因此,对于一个置换 \(P\),设其分解成所有轮换的大小为 \(s_1,s_2,\dots, s_k\),贡献为 \(2^{\sum\limits_{i = 1}^{k}\left\lfloor\frac {s_i}2\right\rfloor+\sum\limits_{i, j, i<j}\gcd(s_i, s_j)}\)。
直接 \(O(n!)\) 枚举置换显然不现实,注意到我们只关心轮换的大小,因此可以拆分数枚举,根据经典结论,\(p(n) \sim \dfrac{1}{4n\sqrt3 }\exp(\pi\sqrt{\dfrac{2n}3})\)。
每个拆分方案 \(s_i\) 的方案为 $\dfrac{1}{n!} \times \dfrac{n}{\prod\limits_{i = 1}^{k}s_i!\sum\limits_{i = 1}^{p}cnt_i!}\times \prod\limits_{i = 1}^{k}(s_i - 1)! = \dfrac{1}{\prod\limits_{i = 1}^{n}cnt_i!\times \prod\limits_{i = 1}^ks_i} $,其中 \(cnt_i\) 表示长度为 \(i\) 的轮换个数,显然长度相同的轮换是没有区别的。
时间复杂度 \(O(p(n) \times poly(n))\)。
[清华集训2017]生成树计数
若有 \(n\) 个连通块,每个大小为 \(a_i\),每个连通块度数为 \(d_i\) 连成一棵树的方案为:\(\prod\limits_{i = 1}^{n}a_i^{d_i}\times\dfrac{(n - 2)!}{\prod\limits_{i = 1}^{n}(d_i - 1)!}\), 枚举每个点的度数
注意到前后两个形式类似,考虑设 \(A(x) = \sum\limits_{k \geq 1}\dfrac{k^{2m}}{(k - 1)!}x^k\) ,\(B(x)= \sum\limits_{k \geq 1}\dfrac{k^m}{(k - 1)!}x^k\),则 \(= [x^{n - 2}] \sum\limits_{i = 1}^{n}A(a_ix)\prod\limits_{j \neq i}B(a_jx) = (\sum\limits_{i = 1}^{n}A(a_ix)) \times (\prod\limits_{i = 1}^{n}\dfrac{A(a_ix)}{B(a_ix)}))\)。
考虑前面一部分,\(\sum A(a_ix)\)的 \(k\) 次项系数为 \(A[k] \times (\sum\limits_{i = 1}^{n}a_i^k)\),可以预处理每个 \(k\) 次幂 \(c_k = \sum\limits_{i= 1}^{n}a_i^k\) 计算。
考虑后面一部分,经典 Ln + Exp:\(=\exp(\sum\limits_{i = 1}^{n}\ln(\dfrac{A(a_ix)}{B(a_ix)})\)。同样可以利用 \(c_k\) 计算,但 \([x^n]F^k(x) = [x^{-k}]\dfrac 1 n G^{-n}(x)\)。
鸽子的老家
谨防新型信息诈骗,主要特征有:
- 含义不明的数字,例如 \(1.242803739^{(m - 1)(m - 2)}\)。
- 表述奇怪的函数,如 \(\sum\limits_{1 \leq a_1 <a_2<\dots <a_m \leq n}[\prod\limits_{1 \leq i < j \leq m}|P(a_i, a_j)\cap S|]\)。
- 非常的模数,如 \(1914270647\)。
随便找一个 \(a_i\) 作为根,显然有 \((m- 1)\) 条路径至少有 1 的权值,考虑路径两两配对,至少有 \(\dfrac{(m-1)(m-2)}2\) 个 2,由于 \(\sqrt 2 > 1.2428\dots\),问题就是找 \(m\) 个点,使得任意两对点之间有一条关键边。
时光倒流,考虑非关键边形成的连通块,显然每个连通块最多选一个点,方案为 \(a_i\),答案即是选择 \(m\) 个点的总方案,背包即可,每次合并两个连通块只用撤销两个背包,加入一个背包。
时间复杂度 \(O(nm)\)。
鸽子做加法
首先整数和小数可以分开考虑,每个分数向下取整后都可以写成一个整数 + 正真分数。利用 \(a \ \mathrm{xor} \ b = a+b - 2 (a \ \mathrm{and} \ b)\),于是可以只用算与。前面的非循环节部分不好处理,可以把分母不断 \(/2\) 变成奇数,此时两个都必然是纯循环小数。
考虑如何求纯循环小数的循环节,这是个经典问题:
看做二进制除法,若分母 \(<\) 分子则商 0,否则商 1,分子减去分母,每次将余数 \(\times 2\) 就是答案。循环节即是分子第二次为 \(p\) 的位置 \(-1\)。 显然 \(\dfrac p q\) 的循环节长度不会超过 \(q\)。设两个分数的循环节长度分别为 \(l_1, l_2\)。
显然答案的循环节长度不超过 \(m = \mathrm{lcm}(l_1,l_2)\),同时也是一个纯循环小数,因此只用算出在前 \(m\) 位的表示,再利用等比数列 \(a+a2^{-m}+a2^{-2m} = \dfrac{a}{1 - 2^{-m}}\) 计算。
显然 \(ans_i = a_{i \bmod l_1} b_{i \bmod m_2}\) ,直接计算就是 \(O(m)\) 的,考虑利用同余的性质优化:对于任意一个 \(i\),\(j\),\(a_i\) 和 \(b_j\) 同时出现的位置 \(x\) 满足:
直接用扩展 CRT 解 \(x\) 显然没有前途,考虑 \(l_1 \perp l_2\) 时,直接用普通 CRT,则$ x = i \times l_2 \times l_2^{-1} + j \times l_1 \times l_1^{-1}$,其中 \(l_2^{-1}\) 为 \(\bmod l_1\) 意义下 \(l_2\) 逆元注意到贡献为 \(2^{-x} = 2^{-i\times l_2 \times l_2^{-1}} \times 2^{-j \times l_1 \times l_1^{-1}} \times 2^{m[i+j \geq m]}\) 关于 \(i, j\) 两维几乎是独立的,只需要在 \(i + j \geq m\) 时加上 \(2^{m}\) 的贡献,可以排序后分别计算 和 \(<m\) 的和 \(\geq m\) 的。这样就可以 \(O(n\log n)\) 计算。
当然 \(l_1,l_2\) 不一定互质,此时任选两个下标 \(i, j\) 不一定能对应,但注意到条件为 \(\gcd(l_1,l_2) \mid i - j\) ,因此可以按照模 \(d = \gcd(l_1, l_2)\) 余数进行分组,在相同组的可以按照上面的计算,在不同组的,显然不能两两对应。在同一组的满足互质的性质。
CF434E
正难则反,设两点之间边权为 1 表示 \(G(S(s, e)) \equiv x(\bmod y)\),否则为 0。计算非法三元组数量,设 \(x \to y \to z, x \to z\),规定 \(x \to z\) 的颜色后,\(x \to y \to z\) 有三种情况。但直接统计三元数量不好统计。
观察非法三元组形态,必然存在一个点,和它有关系的边分别为 0 / 1,在一个坏三元组中会恰好有两个这样的点,因此算出这样的点个数 \(/ 2\) 即可。
若钦定 \(x\),则满足 \(y \to x\) 为 0,\(z \to x\) 为 1;或 \(y \to x\) 为 1,\(z \to x\) 为零,简单的讨论后,设 \(in_{0, 1}\) 表示 0 / 1 入边个数,\(out_{0, 1} 同理\),对于一个点,方案总和为:
\(in_0 \times in_1 \times 2+out_0 \times out_1 \times 2+in_0 \times out_1 +in_1 \times out_0\)。
\(in_{0, 1}, out_{0, 1}\) 的计算点分即可。由于 \(y\) 是质数,路径满足可减,容易开桶统计。
CF375C
trick:判断一个点是否在多边形内部可以引一条该点为端点的射线,若射线与多边形奇数个交点则在内部。
因此,设 \(dp_{x, y,S}\) 表示当前在 \((x, y)\),只考虑当前多边形的边 \(S\) 中的点在内部。我们可以钦定所有射线都是平行于 \(x\) 轴的就可以得到新的状态。
注意边界上的点不能计算入答案,一种处理方法是强制边界点不能选 B 和 数字,且横着的线段可以忽略,对于竖着的线段,钦定左闭右开即可。
用 BFS 转移即可。
CF1336F
将两条路径的交分成两部分,一种 LCA 相同,一种不同。
设当前链分别为 \(A,B\),端点为 \(s_A, t_A, s_B, t_B\),设 \(l_A = \mathrm{LCA}(s_A, t_A), l_b = \mathrm{LCA}(s_B, t_B)\) ,\(dfn_{s_A} < dfn_{t_A}, dfn_{s_B}< dfn_{t_B}\)。
-
若 \(l_A \neq l_B\):
假设 \(l_A\) 为 \(l_B\) 祖先,从根自顶向下进行 DFS,在更深的 LCA 处统计答案,在 \(E,F\) 处单点加,在 \(B\) 处统计答案,找到 \(B\) 向 \(G, H\) 分别走 \(k\) 步到达的点,进行一次子树求和。
-
若 \(l_A = l_B\):
枚举 \(l_A = X\)。
由于保证了 dfn 序的大小关系,固定 $s_A $ ,则 \(t_A\) 的相对顺序有三种:2,3,4。其中 34 是本质相同的,因为都是同一子树的不同点匹配。
将 \(t_A\) 挂在 \(s_A\) 上,枚举 \(E\) 的两个子树进行启发式合并。设 \(E\) 向 \(t_A\) 方向走 \(k\) 步到达 \(H\) (若走过 \(t_A\) 显然非法,不足 \(X\) 则直接到达 \(X\)),询问在起点另一颗子树内的,且终点在 \(H\) 子树的点对,显然可以启发式合并 + 线段树合并。
对于 \(t_A\) 相对顺序为 2 的情况,此时两个路径只有一端有相交。
将所有链按照起点的 dfs 序排序,枚举到 \(s_A, t_A\) 时,在 \(t_A\) 单点加;枚举到 \(s_B, t_B\) 时,从 \(X\) 走 \(k\) 步到 \(D\),查询 \(B\) 的子树和。
时间复杂度 \(O(n\log^2 n)\)。
总结:
- 根据题目的提示也许有助于分讨。
- 加强条件,从而减少可能的方案,取而代之的是繁琐的分讨。
- 线段树合并 + 启发式合并可以暴力地解决问题。