Loading

【题解】UOJ Round #14

// created on 22.09.28

A. 最强跳蚤

首先将每个数变成 \(\prod p\) 的样子肯定不影响。接着考虑点分治,处理每个点到分治中心的积(仍然写成上面的形式)。那么跨越分治中心的合法路径一定满足,端点的积相等。

但注意到我们无法承受这样的数量级。直接哈希肯定不行,因为我们处理的时候需要用到 \(\gcd\)(将重复部分去掉)。我们单独维护每个位的情况,然后维护哈希值就行了。

另外一种简单的做法就是:我们对每个质数赋一个随机权值。这样合并的过程就是异或。直接在树上做的话,对应的祖先链是一样的,因此只需要数相同权值的点数了。

简单题不写代码。

B. 人类补完计划

发现其实就是,要满足 \(S_e\) 是基环树。然后权值是 \(2\) 的非叶子节点数量次方。结合数据范围不难判断出是集合幂级数题 .. 但是这并不意味着我们要直接往集合幂级数的方向思考!

我们考虑枚举基环树的点集 \(S\),并且考虑其叶子集合 \(T\) 。令 \(f(S)\) 表示 \(S\) 的答案,\(g(S)\) 表示 \(S\) 呈基环树的方案数,我们有:

\[f(S)=2^{|S|}\sum_{T\subseteq S}g(S-T)(2^{-1}-1)^{|T|}h(S-T,T) \]

中间的系数是构造出来的,目标系数是 \(2^{-|T|}\)

如果可以求得 \(g(S)\) 就可以 \(3^n\) 求出答案。考虑 \(g(S)\) 相当于要求每个点钦定一个出边,并且全图联通。看到联通就知道集合幂级数了。求出任意方案数后 \(\ln\) 过来就行了。

对于长度为 \(2\) 的环我们也会计算一次,而其方案数其实和生成树方案数是对应的,只需要对每个 \(S\) 求生成树个数即可。于是总时间复杂度 \(O(2^nn^3+3^n)\)

提交记录:Submission #585395 - Universal Online Judge (uoj.ac)

C. 思考熊

直接点分树好像可以做,不过空间难以接受,我们的目的也不至于此。本题的主要做法还是 带删二进制分组,和 Unknown 是一样的。

首先我们考虑点集的虚树怎么处理答案:我们在虚树上 DP,对于每个点,求出往上走最远的关键点的距离 \(g_u\),以及往下走最远的关键点距离 \(f_u\) 。对于单次询问 \(q\),二分找到 DFN 序比 \(q\) 小的最大的,和比 \(q\) 大的最小的,取更低的 LCA \(t\),意味着 \(q\rightarrow t\) 恰好走到虚树上。问题变成询问 \(t\),此时二分找到 DFN 序比 \(t\) 大的第一个点,就是 \(t\) 下面第一个点 \(p\),用 \(f_p,g_p\) 更新答案即可。

现在要做的就是合并虚树,我们考虑建一棵完全线段树。支持删除节点,只需要将点删除,然后将受到影响的点打上标记。我们希望一层只有至多一个点有标记。因此在加入节点合并时,需要即时重构。

分析复杂度?询问的话,因为一层至多一个点有标记,复杂度为 \(\log^2n\) 。而修改复杂度,对于第 \(i\) 层,除非删除 \(2^i\) 个点,或者加入 \(2^i\) 个点,否则都不能改变状态。而改变状态更新的块是 \(O(1)\) 个,复杂度 \(O(2^i)\) 。因此总复杂度是 \(O(n\log^2 n)\),还有一个 \(\log n\) 是虚树的部分。

有空我肯定写代码!

代码细节:每个点维护一个 "大小",当 "大小" 归零时清空。每次修改仿照线段树,找到链上点。如果是删除就一路打标记,删除空节点。如果是插入就重建叶子,然后往上每一层考虑合并,如果恰好满插,并且没有非法标记,就考虑更新当前层标记情况(考虑上一个点有无标记),然后重建;如果有非法标记,就先不管。查询的时候递归判一下空节点就行。

posted @ 2022-09-28 16:59  Qiuly  阅读(76)  评论(0编辑  收藏  举报