HAOI 2018 大赏
先祭上出题人题解.
然而没有找到 Round 2 的官方题解 (
「HAOI2018」奇怪的背包
要命的 $\gcd$…
题目链接
解题思路
所求即为满足
的不同集合 $S$ 个数, 其中 $a_i > 0$, 表示物品选择个数.
写成不定方程的形式, 即
根据裴蜀定理, 该方程有解, 则需满足 $\gcd(V_1, V_2, \ldots, P) \mid w$.
可以发现, 对所有值, 同 $P$ 取 $\gcd$ 并不会影响答案, 那么枚举 $P$ 的约数, 直接 DP 即可.
直接 DP… 令 $d(P)$ 表示 $P$ 的约数个数, 容易得到时间复杂度 $O(nd(P)$ 的做法, 但是可以进一步优化.
枚举 $P$ 的约数, 对于同 $P$ 取 $\gcd$ 相同的 $V_i$, 在 DP 时一起算即可.
具体地, 设 $f(i, j)$ 表示选择 $P$ 前 $i$ 个约数, 得到 $P$ 的第 $j$ 个约数的方案数. 记 $s(i)$ 表示第 $i$ 个约数在 $\gcd(V_j, P)$ 中的出现次数, $d_i$ 表示 $P$ 第 $i$ 个约数. 那么有
由于 $P$ 的约数中可能存在一些整除关系, 最后 $O(d^2(P))$ 枚举一遍把贡献加起来就好了.
时间复杂度 $O(\sqrt{P} + n \log P + d ^ 2(P) \log P)$.
另外祭上某张流传已久的表格…
图源 UOJ 用户群, 至少我是从那里找到的
代码实现
1 | // LOJ #2523 |
「HAOI2018」反色游戏
题目链接
解题思路
首先有一个简洁的结论, 所求的方案数为 $2^{m - n + p}$, 其中 $m$ 为边数, $n$ 为点数, $p$ 为连通分量个数.
官方题解从图论和线性代数两个角度解释了这个结论, 然而我只能流下学不会线性代数的泪水…
于是从图的连通性入手解释这个结论.
单独考虑每一个连通分量, 如果该连通分量中存在偶数个黑点, 那么一定存在可行方案; 否则不存在.
考虑将该连通分量中的黑点任意两两配对, 由于存在偶数个黑点, 所以没有多余. 可以发现
- 对于两黑点间的任意一条路径, 不论经过的边数是奇是偶, 总可以构造出一种方案, 使得路径上只有这两个黑点颜色反转.
- 对于这些路径的交, 每次把边选 / 不选的状态取反, 不会影响到原来的局面.
如果存在奇数个黑点, 则不存在以上性质… 因而不存在合法方案.
同时我们知道了, 配对数和方案数是等价的. 换言之, 每种黑点两两匹配的方案, 唯一对应着一个合法解.
所以对于一个点数为 $n$ 的连通分量, 有解的情况有 $2^{n-1}$ 种 (拿组合数加起来推一推可知), 由于边数为 $m$, 共 $2^m$ 种情况, 所以每种有解的情况下, 解的个数为 $2^{m-n+1}$. 对 $p$ 个连通分量进行推广, 答案即为 $2 ^ {m - n + p}$.
似乎还可以从另一个角度解释? 参见 https://www.cnblogs.com/xjqxjq/p/11781185.html.
知道结论后的做法就很明晰了, 跑 tarjan 求割点, 讨论是否有解, 以及删边后整体边数, 点数, 连通分量个数的变化即可.
时间复杂度 $O(n + m)$.
代码实现
1 | // LOJ #2524 |
「HAOI2018」字串覆盖
题目链接
解题思路
出题人称本题算法并不优美… 其实也的确不怎么优美 = =
LOJ 上的题面并没有所有数据点的限制, 可以参考洛谷的题面: https://www.luogu.com.cn/problem/P4493.
观察数据点的限制, 可以发现 $r-l$ 的限制非常独特, 于是分两种情况讨论:
$r-l \ge 2000$
此时串 $P$ 较长, 那么 $P$ 在 $T$ 中匹配次数较小.
考虑覆盖操作, 每次选择位置最靠前, 且未被覆盖的位置去覆盖, 直到单次对答案的贡献 $\le 0$. 此时得到的答案一定是最优的.
设匹配次数为 $p$, 利用 SAM 以及线段树合并维护 $endpos$ 集合的套路, 可以在 $O(p \log n)$ 的时间完成单次询问.
具体地说, 对串 $A$ 建 SAM, 在线段树上维护 $endpos$ 中最靠后位置. 对于串 $P$, 利用倍增找到其在 SAM 上对应节点. 如果可以匹配, 每次在线段树上二分, 找到一个最靠前位置, 累计答案, 并继续匹配.
对于 $50 < r-l < 2000$ 的情况, 数据中限制了该情况的出现次数, 直接按以上方法做即可.
$r-l \le 50$
此时串 $P$ 较短, 那么串 $A$ 中所有长度为 $|P|$ 的子串只有 $n - |P| + 1$ 种. 考虑用倍增处理所有的这些子串.
参考 PhantasmDragon 的思路, 对于串 $A$ 中一个从位置 $i$ 开始的子串 $s$, 设 $\operatorname{nxt}(|s|, i, j)$ 表示后 $2^j$ 个字符同 $s$ 相同的字符串的左端点位置.
同时记录 $f(|s|, i, j)$, 表示此时对答案的贡献.
单次查询时形同上面一种情况, 先找到串 $P$ 对应在 SAM 的节点, 以及第一个匹配位置, 然后倍增统计答案即可.
对于预处理, 枚举每个长度, 对于每个不同的子串, 利用哈希和双端队列维护 $\operatorname{nxt}$. 接着套路倍增即可.
直接预处理似乎不太可行, 可以将所有询问离线, 按串 $P$ 长度排序, 遇到不同长度直接重新计算倍增数组就好了.
单次询问时间复杂度 $O(\log n)$.
代码实现
直 接 自 然 溢 出 啥 事 没 有
然后流下了只会写双哈希的泪水…
1 | // LOJ #2525 |
「HAOI2018」苹果树
题目链接
解题思路
先吐槽出题人不把模数的限制写详细一点…
不过不怎么影响做题来着.
首先可以发现, 期望再乘 $n!$ 就是大忽悠 = =, 所求即为所有节点数为 $n$ 的二叉树, 两两距离之和的和.
有一个性质, 一条边 $(i, j)$ 被经过的次数为 $s (n - s)$, 其中 $s$ 为 $j$ 对应子树大小. 考虑到 $n \le 2000$, 可以枚举一个点, 以及对应这个点对应子树大小来计算答案.
设当前枚举到第 $i$ 个点, 前 $i$ 个点的位置都确定了, 且节点 $i$ 某一个儿子的子树大小为 $j$.
再稍微解释一下, 前 $i$ 个点的选择顺序是一个排列, $i$ 到其某一个儿子的边被经过 $j(n-j)$ 次.
考虑大小为 $j$ 子树的内节点排布情况, 也就是在剩余 $n-i$ 个节点中挑出 $j$ 个节点做一个排列, 由于是二叉树, 方案数 $\times 2$.
再考虑该子树外的情况, 对于剩下的 $n - j - i$ 个节点, 不能挂在该子树内, 依次有 $i, i+1, \ldots, n-j-1$ 种选择 (因为每次都新加了一个节点), 由乘法原理乘起来就好了.
似乎做完了, 其实已经做完了, 后面的累乘预处理一下就好了.
其实后面的累乘化简一下就消掉了, 也就是
总感觉这个式子有着什么高妙的组合意义.
时间复杂度 $O(n^2)$.
代码实现
代码中使用了 1 式.
2 式代码也交在 loj 上了, 常数小了一倍…
1 | // LOJ #2526 |
「HAOI2018」染色
题目链接
解题思路
如果想到了二项式反演, 那么这道题还算套路吧…
可惜没有, 溜了溜了, 还在化卷积上浪费时间, 退役稳了
设 $f(x)$ 表示钦定 $x$ 种颜色出现 $S$ 次, $g(x)$ 表示恰好 $x$ 种颜色出现 $S$ 次.
记 $N = \min \{ m, \lfloor \dfrac{n}{S} \rfloor \}$, 那么答案即为
先考虑如何计算 $f(x)$, 也就是在 $m$ 种颜色中挑出 $x$ 种出现 $S$ 次, 任意排列, 且不管其余位置的颜色, 那么可以得到
(中间部分是一个多重集合的排列数, 为了方便就拆开了)
对于 $f(x)$ 和 $g(x)$, 有
二项式反演一通之后可以得到
把组合数展开, 得
接下来, 卷积登场. 记 $h(x) = \frac{(-1)^{N-x}}{(N-x)!}$, 那么
用 NTT 优化计算即可. 时间复杂度 $O(n \log n)$.
代码实现
1 | // LOJ #2527 |