「ZJOI 的部分题解整理」


ZJOI2017D1:http://jiruyi910387714.is-programmer.com/posts/209073.html

ZJOI2017D2:http://jiruyi910387714.is-programmer.com/posts/212169.html

ZJOI2018D1:http://jiruyi910387714.is-programmer.com/posts/212412.html

ZJOI2018D2:http://jiruyi910387714.is-programmer.com/posts/212639.html


会把之前的 ZJOI 题解(陆续更新) + 新的 ZJOI 题解整合在一起。

水平有限,所以仅有一部分题解。

从 ZJOI2016 开始,之前的题如果有时间再补上吧。

题目在 uoj/loj 上都可以找到。


「ZJOI2016」旅行者

网格图分治,每次选 \(n, m\) 中较大的进行分割。

对于跨越分割线的询问,枚举分割线上的点求最短路。

\(S = n\times m\),复杂度 \(O(S\sqrt{S}\log S)\)


「ZJOI2016」小星星

\(f_{x,i,s}\) 表示把 \(x\) 映到 \(i\) 上,子树内所有映到 \(s\) 上的方案数,复杂度 \(O(n^2\times 3^n)\)

发现是子集卷积,考虑对占位多项式 \(g_{x,i,t,s} = [popcount(s)=t]\times f_{x,i,s}\) 进行 fwt,中途不需要反演回来,复杂度 \(O(n^4\times 2^n)\)

注意到对于某一个 \(x\),只有当 \(t = size(x)\)\(g_{x,i,t,s}\) 才有值,所以可以省掉一维,复杂度 \(O(n^3\times 2^n)\)

用容斥可以推得类似的做法。


「ZJOI2016」大森林

将树的序列看作时间轴,从左往后扫描,在 \(l\) 处加入操作,在 \(r + 1\) 处弹掉操作。

可以通过简单转化保证操作 1 对应的树全部含点 \(x\),那么 0 操作的区间不再重要。

考虑操作 1 对应的修改,即将一些点的父亲全部修改为某个点,可以通过建虚点 + lct 完成这一操作。

注意询问不能直接查路径上的实点数量。


「ZJOI2016」线段树

\(dp(i,l,r,x)\) 表示第 \(i\) 次操作以后,\(a'_{l\dots r}\leq x\)\(a_{l-1}>x,a_{r+1}>x\) 的概率。即 \(\leq x\) 的极长区间。

注意到转移时 \(x\) 并没有影响,\(x\) 只影响初态 \(dp(0,l,r,x)\)

且已知 \(dp\) 后求答案只需要 \(\sum_{x}dp(q,l,r,x)\)\(dp(q,l,r,\max\{a_i\})\),因此可以去掉 \(x\) 这一维。

时间复杂度 \(O(n^3)\)


「ZJOI2017」仙人掌

可以将问题转化成 “树上不交链划分”,这里的不交指没有公共边。

考虑求出每个点 \(x\) 的贡献,发现只与 \(x\) 的度数 \(deg(x)\) 有关,记作 \(f_{deg(x)}\)

预处理 \(f\) 即可。


「ZJOI2017」树状数组

正常做只有当 \(x\leq y\)\(x\to y\) 产生贡献,反着做即 \(x\geq y\)\(x\to y\) 产生贡献,即后缀和(注意特判 \(0\))。

那么等价于查询 \(A_{l-1} = A_r\) 的概率,树套树即可(再次强调,注意特判 \(l=1\))。


「ZJOI2017」多项式

首先有个结论:\(f^2(x) = f(x^2) \bmod 2\)。证明直接展开观察。

考虑对 \(f(x)\) 维护所有 \(2^{\max(n, k)}\) 种长度为 \(\max(n, k)\) 的子串的出现次数,支持两种操作 \(f(x)\to f(x^2), f(x)\to g(x)f(x^2)\),其中 \(g(x)\) 是原字符串。

新的字符串中所有长度为 \(\max(n, k)\) 的子串可以对应回原字符串的某个长度为 \(\max(n, k)\) 的子串,为了处理的方便,我们唯一对应到最前面一个。

为什么说这样处理方便?\(f(x)\to f(x^2)\) 倒无所谓,对比 \(g(x)f(x^2)\)\(g(x)\) 单独乘 \(f(x^2)\) 中某个长度为 \(\max(n, k)\) 的子串,两个乘出来的结果实际上只有最高的两位是相同,所以可以只维护长度为 \(\max(n, k)\) 的子串的出现次数来进行转移。

但是这种处理方式不能适用于最前和最后的,因此还需要单独维护最前最后若干个。

区间查询可以转成前缀查询,在转移时再加上一个截断操作即可。时间复杂度 \(O(2^{\max(n, k)}m)\)

我写了个 \(O(2^n\log mk)\) 的不知道在干啥的代码,大概是只能在 loj 跑过去的假做法。


「ZJOI2017」线段树

询问可以拆成两条链 \(l\to lca\)\(r\to lca\)。可以考虑使用倍增找到询问点 \(u\) 的位置,并维护 “被定位的点” 的信息。


「ZJOI2017」字符串(没写)

首先,可以通过分块维护 hash 实现 \(O(\sqrt{n})\) 修改,\(O(\log n)\) 查询 lcp。

对于字符串 \(t\),我们称它的后缀 \(t[i:]\)待选最小后缀,当且仅当存在以 \(t\) 为前缀的 \(t'\)(即在 \(t\) 后加若干字符得到 \(t'\))使得 \(t'[i:]\) 成为最小后缀。

对于 \(t\) 的某两个后缀,如果它们不存在前缀关系,则直接扔掉字典序大的;否则说明短的是长的 border。这样得到一系列互为 border 的待选后缀。

引理:如果 \(p\)\(q\) 的 border,且 \(|q| / 2 < |p| < |q|\),则 \(p\) 不可能是待选最小后缀。

首先,此时必然存在一个 \(p'\)\(p\) 的 border 且 \(|p'| \leq |q| / 2\)

在这种情况下,要么 \(q\) 优于 \(p\) 优于 \(p'\),要么 \(p'\) 优于 \(p\) 优于 \(q\)

这得到一个重要结论:我们所需要维护的后缀集合其实很小。

那么可以使用线段树进行维护,每次上传时合并两个大小为 \(O(\log n)\) 的后缀集合,合并一次复杂度 \(O(\log^2 n)\)(注意求 lcp 是 \(O(\log n)\) 的)。

因此,总复杂度 \(O(m\sqrt{n} + m\log^3n + n\log^2n)\)

实现上好像没有什么特别的困难,不写了。


「ZJOI2018」历史

考虑每个点 \(x\) 的贡献,记 \(sum_x=\sum_{y\in subtree(x)}a_y\),只需要判断是否存在一棵子树的 \(sum_{ch} > \frac{sum_x}{2}\)(或者 \(a_x > \frac{sum_x}{2}\))。

注意到所有点的上界可以同时取到,因此这就是答案。那么只需要动态维护每个点满足 \(sum_{ch} > \frac{sum_x}{2}\) 的重儿子 \(ch\) 即可。

考虑像 lct 一样每条重链用一棵平衡树维护,此时内层 splay 森林的复杂度分析一样,轻重边切换的复杂度分析需要稍微改改,还是可以证得 \(O(n\log n)\) 的复杂度。

(这个思路还可以用于动态维护重链剖分,即今年北大集训的 D3T3)。


「ZJOI2018」迷宫

可以建出最基础的自动机:共 \(K\) 个点,代表模 \(K\) 下的完全剩余系。

(以下运算如非特殊说明,默认在模 \(K\) 意义下进行)

两个结点 \(x, y\) 可以合并的充要条件:

对于任意非负整数 \(i\) 与任意非负整数 \(r < m^i\)

满足 \(m^ix + r = 0\)\(m^iy + r = 0\) 同时成立或者同时不成立。

据此,有一个 trivial 的暴力:

从小到大遍历所有 \(i\),将 \((-m^i, 0]\) 里面存在的结点全部提取出来,这些点不能再和其他点合并。

然后将剩下的点 \(x_1, x_2, \dots, x_t\to mx_1, mx_2, \dots, mx_t\),如果 \(mx_i = mx_j\) 则合并,进行下一轮的迭代。

如果没有点存在,则迭代结束。由于某一时刻会有 \(m^i \geq K\),因此迭代总会结束。

然后考虑加速这一过程。

\(d_i = \gcd(m^i, K)\),则在第 \(i\) 轮中存在的点 \(x\) 满足 \(d_i | x\)

(1)如果 \(d_k = d_{k + 1}\)(或者说 \(d_{k + 1} / d_k = \gcd(m, K / d_k) = 1\)),则在第 \(k\) 轮及其之后不会再有点会被合并,因此可以直接在第 \(k\) 轮停下。

(2)如果所有 \(0d_k, 1d_k,\dots\) 在第 \(k\) 轮中都存在,那么 \(0d_{k + 1}, 1d_{k + 1}, \dots\) 在第 \(k + 1\) 轮中都存在的充要条件为 \(K / (d_{k + 1} / d_k) \leq K - m^k\)

这是因为从 \(k\to k + 1\) 将会有 \(d_{k + 1} / d_k\) 个结点合并成一个,这些结点在模 \(K / (d_{k + 1} / d_k)\) 意义下相同,因此只需要保留前 \(K / (d_{k + 1} / d_k)\) 个即可生成下一轮中的所有数。

反过来当 \(K / (d_{k + 1} / d_k) > K - m^k\) 时,由于 \(d_k \neq d_{k + 1}\),此时有 \(m > 1, d_{k + 1} / d_k > 1\),那么可以推出 \(m^{k + 1} > K\),因此第 \(k\) 轮及其之后不会再有点会被合并(毕竟在 \(k + 1\) 轮时就停下来了)。

(3)如果以上两个条件判定后都没停下来,则此时必然有 \(0d_k, 1d_k,\dots\) 在第 \(k\) 轮中都存在,那么被提取出来的结点数量即为 \(m^k / d_k\)

当然,条件 1, 2 可以整合在一起,因为 \(d_k = d_{k + 1} \Rightarrow K / (d_{k + 1} / d_k) > K - m^k\)

官方题解说复杂度是 \(O(T\log K)\)。但求 gcd 也要 \(O(\log K)\) 求,所以我觉得应该是 \(O(T\log^2K)\)


「ZJOI2018」胖

考虑二分每个点 \(x\) 所能更新的区间 \([l_x, r_x]\) 对应的 \(l_x, r_x\)

需要找到 “能在 \(x\) 到达之前到达二分点 \(mid\)\(y\),距离 \(mid\) 的最短距离”,可以预处理 st 表 + 二分查找。

时间复杂度 \(O(n\log^2n)\),此处认为 \(n, \sum K\) 同阶。注意点的贡献不要算重。

本题存在 \(O(n\log n)\) 的做法,详见 https://blog.csdn.net/zxin__/article/details/82925838。


「ZJOI2018」保镖(没写)

官方题解:https://blog.csdn.net/qq_16267919/article/details/80100413

(1)凸包点数转化成三角剖分的数量(利用欧拉定理)。为了方便,特化成 Delaunay 三角剖分。

定义经过至少三个点且严格内部不含任何点的圆为内圆

内圆与 Voronoi 图的顶点一一对应;进一步地,由于 V 图和 D 剖是对偶的,因此内圆和三角剖分中每个三角形一一对应。

定义经过至少三个点且严格外部不含任何点的圆为外圆

(2)反演中心在圆内,则内圆变外圆,外圆变内圆;否则内圆依然是内圆,外圆依然是外圆。

因此只要找出所有内圆和外圆,最后做圆与矩形的面积交即可。

圆的方程 \(x^2 + y^2 + Dx + Ey = F\)

考虑记 \(z = x^2 + y^2\),则该方程可以改写成平面方程 \(z + Dx + Ey = F\)

也即,将平面点 \((x, y)\) 映到三维抛物面 \((x, y, x^2 + y^2)\) 上,圆的分割变成了平面分割。

由于平面是线性的,所以方便很多。

(3)内圆和三维凸包中的下凸面一一对应,外圆和三维凸包中的上凸面一一对应。

做一个三维凸包即可,这道题 \(O(n^2)\) 都可。

因为实在不会写三维凸包,于是咕掉咕掉。

由于 V 图和 D 剖是对偶的,所以内圆个数、V 图顶点数都是 \(O(n)\) 的。这个结论可以应用于 「ICPC World Finals 2018」熊猫保护区

另外,有一道同样是 “映到三维抛物面” 这一想法的题目 CF549E,本质上判三维凸包是否有交。

很好看的 gif(关于 V 图的):

img

其他的碎碎念:

关于 \((x, y)\mapsto (x, y, x^2 + y^2)\) 这一变换,我感觉很奇妙。

是否其他二次曲线都有类似的变换呢?或者说,一些其他曲线还可以映到更高维的线性对象上?

这个做法抽象了问题的本质吗?上面的 CF549E 事实上代码实现并没有依赖于三维凸包。那么,是否有更直接的推导呢?


「ZJOI2019」麻将

我没打过麻将,所以不会用专业术语。

考虑给定一个牌组,如何判断是否可胡。

自然的想法是设 \(f_{i, 0/1, j, k, t}\) 表示考虑前 \(i\) 种牌,取过/没取过对子,第 \(i - 1\) 种牌剩 \(j\) 张,第 \(i\) 种牌剩 \(k\) 张,已经有 \(t\) 个对子,的最大面子数。

如果 \(\forall 0\leq j, k\leq 4,0\leq t < 7\),都有 \(f_{n, 1, j, k, t} < 4\),则不可胡。

注意到三个相同的 \(i, i + 1, i + 2\) 形式的总可以换成三个 \(i, i, i\),则另一个较优的状态设计为:保留 \((i - 1, i)\)\(j\) 组,保留 \(i\)\(k\) 张。则此时有 \(0 \leq j, k\leq 2\)

观察到 \(f_i\) 实际上保留了前 \(i\) 种牌的所有信息,这样算出本质不同的不可胡的牌组数的一个上界是 \(5^{2\times 3\times 3\times 7}\)

不过这个上界非常松,实际上搜出来本质不同的不可胡的牌组数只有 2091 种。

搜出所有牌组与它们之间的转移(实际上形成了一个 DFA),再回到原问题就比较套路了:设 \(dp_{i, j, s}\) 表示前 \(i\) 种牌共选了 \(j\) 张牌,得到的牌组状态为 \(s\) 的方案数。

\(j\) 是为了方便算期望。由于牌互不相同所以转移时还要乘组合数。


「ZJOI2019」线段树

考虑 dp:定义 \(dp(0/1, 0/1, x)\) 表示 x 的祖先结点是否有 tag,x 本身是否有 tag,这 4 种情况分别对应的方案数。

观察 dp 的转移,发现只有线段树上单点修改/子树修改,单点询问/子树询问。

直接维护一下线段树上的 单点 dp 值/转移矩阵 与 子树 dp 值/转移矩阵 即可。

时间复杂度 \(O(n\log n)\)


「ZJOI2019」Minimax 搜索

记根对应权值为 \(rt\),尝试求出 \(\max_{i\in S}|i-w_i|\leq k\) 的集合数。首先特判集合中包含 \(rt\) 的情况。

给定 \(k\),可以求出每个 \(> rt\) 的叶子是否可以 \(< rt\),每个 \(<rt\) 的叶子是否可以 \(> rt\)

\(f(x)\) 表示只把 \(> rt\) 的改小使 \(w_x\) 变小的集合数,记 \(g(x)\) 表示只把 \(< rt\) 的改大使 \(w_x\) 变大的集合数,可以 dp。

发现每一个 \(k\) 都要重新 dp,可以按 \(k\) 从小到大的顺序进行动态 dp。


「ZJOI2019」开关

\(q_i=\frac{p_i}{\sum p_i}\)

一种推导方法是使用集合幂级数:

\(f_S\) 表示当前开关状态为 \(S\),到达终态的期望步数。有转移:

\[\begin{cases} f_S &= 1+\sum_{i=1}^{n}f_{S\ \rm{xor}\ 2^i}\times q_i\\ f_0 &= 0 \end{cases} \]

\(I\) 表示全 \(1\) 的序列,给不满足转移的 \(f_0\) 加上偏移量 \(k\),可得卷积式:

\[F\otimes Q + I = F+k \]

\(fwt(F)\times fwt(Q-1)=fwt(k-I)\)

由于 \(fwt(F)_S = \sum_{T}(-1)^{|S\cap T|}f_T\),得:

\[\begin{aligned} fwt(Q-1)_S&=\sum_{i\not\in S}q_i-\sum_{i\in S}q_i-1\\ fwt(k-I)_S&=-\sum_{T\subseteq S}(-1)^{|T|}\times 2^{n-|S|}+k \\ &=-2^{n-|S|}\times\sum_{i=0}^{|S|}{|S|\choose i}(-1)^i+k \\ &=k-[S = \empty]\times 2^n\\ \end{aligned} \]

因此 \(fwt(Q-1)_{\empty} = 0\),推得 \(fwt(k-I)_{\empty} = k-2^n=0\),解得 \(k = 2^n\)

\(S\neq \empty\) 时,有 \(fwt(F)_S = \frac{fwt(k-I)}{fwt(Q-1)} = \frac{2^n}{\sum_{i\not\in S}q_i-\sum_{i\in S}q_i-1}\)

由于 \(ifwt(F)_S = \frac{1}{2^n}\sum_{T}(-1)^{|S\cap T|}f_T\)。则:

\[\begin{aligned} F_S &= \frac{1}{2^n}(\sum_{T\not =\empty}\frac{(-1)^{|S\cap T|}\times 2^n}{\sum_{i\not\in T}q_i-\sum_{i\in T}q_i-1} + fwt(F)_0) \\ &= \sum_{T\not =\empty}\frac{(-1)^{|S\cap T|}\times\sum p_i}{\sum_{i\not\in T}p_i-\sum_{i\in T}p_i-\sum p_i} + \frac{fwt(F)_0}{2^n} \\ &= -\sum_{T\not =\empty}\frac{(-1)^{|S\cap T|}\times\sum p_i}{2\sum_{i\in T}p_i} + \frac{fwt(F)_0}{2^n} \end{aligned} \]

如果已知 \(\frac{fwt(F)_0}{2^n}\),以 \(\sum_{i\in T}p_i\) 为状态作背包 dp 就可以 \(O(n\sum p)\) 算出 \(F\) 的某一项了。

注意到还有条件 \(F_0 = 0\),可以通过这个条件解出 \(\frac{fwt(F)_0}{2^n}\)

也可以用 EGF 推:

\(F(z) = \prod_{i=1}^{n}(\frac{e^{q_iz}+e^{-q_iz}}{2})\) 表示回到原状态的 EGF。

\(G(z) = \prod_{i=1}^{n}(\frac{e^{q_iz}+(-1)^{s_i}e^{-q_iz}}{2})\) 表示永不停止,按到终态的 EGF。

\(\hat F(z),\hat G(z)\) 分别是 EGF 对应的 OGF,则 \(\frac{\hat G(z)}{\hat F(z)}\) 表示终态停止的 OGF,答案即为 \((\frac{\hat G(z)}{\hat F(z)})'|_{z=1}\)

\(F(z)=\sum a_k e^{kz}\),则 \(\hat F(z) = \sum \frac{a_k}{1-kz}\)(此时 \(k\) 形如 \(\frac{\sum_{i\in S}p_i}{\sum p_i}\))。同理 \(\hat G(z)=\sum\frac{b_k}{1-kz}\)。可以背包求出所有 \(a, b\)

由于 \((\frac{\hat G(z)}{\hat F(z)})'|_{z=1} = (\frac{\hat G'(z)\hat F(z)-\hat G(z)\hat F'(z)}{\hat F^2(z)})|_{z=1}\),但是 \(\frac{1}{1-z}\) 不能直接带,所以上下同乘 \(1 - z\)


「ZJOI2019」语言

维护端点在 \(x\) 子树内的链构成的并集,则贡献为链并集中 dfs 序在 \(x\) 之前的点数。

链并集可以通过 \(\sum dep_{a_i} - \sum dep_{lca(a_{i-1},a_i)}\) 计算,其中 \(a_i\) 为按 dfs 序排好的链端点。注意 \(a_i\) 是连成环的,也即还需要计算首尾的 lca。

链并集中 dfs 序在 \(x\) 之前的点数,可以把 \(x\) 加入其中并弹掉 \(x\) 之后的点。

于是线段树合并即可,时间复杂度 \(O(n\log^2 n)\)(求单次 \(lca\) 视作 \(O(\log)\))。


「ZJOI2020」传统艺能(不做)

好像是道水题啊,不想思考,不做了。


「ZJOI2020」序列

\(\mathcal S\) 表示所有操作的集合,每种操作 \(T\in\mathcal S\) 由该操作影响到的所有位置组成。

容易列出线性规划:

\[\begin{aligned} \mathrm{minimize} && \sum_{T\in\mathcal S}x_T & \\ \mathrm{s.t.} && \sum_{i\in T}x_T & = a_i && 1 \leq i \leq n \\ && x_T & \geq 0 \end{aligned} \]

将其化成标准型并对偶:

\[\begin{aligned} \mathrm{maximize} && \sum_{i=1}^{n}a_i\phi_i & \\ \mathrm{s.t.} && \sum_{i\in T}\phi_i & \leq 1 && T\in\mathcal S \\ \end{aligned} \]

首先,我们假设它就是整数规划。

这些不等式对应的实际含义:原序列任意区间的和 \(\leq 1\);奇/偶数位置构成的子序列,任意区间的和 \(\leq 1\)

注意到 \(\phi_i < -1\) 是一定不优的(将其换作 \(\phi_i = -1\) 一定也合法),所以 \(\phi_i\) 的取值只有 \(0, \pm 1\)

那么这些不等式等价于:原序列任意两个 \(1\) 之间至少隔了一个 \(-1\);奇/偶数位置构成的子序列,任意两个 \(1\) 之间至少隔了一个 \(-1\)

然后做一个 \(O(n)\) 的 dp 即可。


「ZJOI2020」抽卡

考虑一个已经抽取 \(i\) 张牌,且仍未合法的局面。抽出该局面的概率为 \(1/\binom{n}{i}\),下一次抽中不重复的期望步数为 \(n/(n-i)\)

因此,设 \(f_i\) 表示 \(i\) 张牌且仍未合法的局面数量,则答案为 \(\sum n/(n-i)\times1/\binom{n}{i}\times f_i\)

考虑求出每个连续段对应的生成函数 \(A_i(x)\),则 \(\prod_i A_i(x)\) 即是我们想要的。

以下设连续段长度为 \(s\),我们在最后加一个空白变成 \(s + 1\)

从组合对象的角度,由于不存在 \(k\) 个连续被抽中的,总可以将其划分成 “\(i < k\) 个抽中的 + \(1\) 个没抽中的”。

划分出来的每一段对应生成函数 \(F(x) = x\frac{1-x^k}{1-x}\),总方案数 \([x^{s + 1}]1/(1-F(x))\)

然而我们并不是求总方案数。考虑求出 \([x^{s + 1}]F^i(x)\),它对应了 “没抽中 \(i\) 个” 的方案数,反过来就抽中了 \((s + 1 - i)\) 个。

这是个经典拉反,可以在预先牛迭求出 \(F\) 的复合逆,再 \(O(s\log s)\) 的时间内求出上述值。

具体来说,设 \(F\) 的复合逆为 \(G\),欲求 \([x^n]F^{0\dots n}(x)\)。由拉格朗日反演:

\[[x^n]F^i(x) = [x^n]x^iG'(x/G)^{n + 1} = [x^{n - i}]G'(x/G)^{n + 1} \]

等价于求 \([x^{0\dots n}]G'(x/G)^{n + 1}\)

posted @ 2020-12-21 17:06  Tiw_Air_OAO  阅读(581)  评论(0编辑  收藏  举报