ずっと ずっと 離さないでいて
[清华集训 2014] 主旋律
这篇题解 写的比较好。主要技巧是:
- 子集反演。
- DAG 上的计数可以枚举入度为 \(0\) 的点,然后去容斥。
- 主旋律本身也是比较经典的题。
Harry The Potter
显然答案上界是 \(n\)。现在要让操作数尽可能小。集合 \(S\) 全用 \(1\) 操作次数为 \(|S|\),现在要让它次数减少,要么集合内部使用 \(|S|-1\) 次 \(2\) 操作后全部变 \(0\),要么把它分成类似的子结构。问题转化为判断一个集合 \(|S|\) 是否能用 \(|S|-1\) 次操作然后全部变 \(0\)。
不妨考虑一个弱化的问题:操作的两个数减去相同的 \(x\)。把 \(2\) 操作看成一条边,发现一定存在一种最优方案使得图上无环,如果有环不如执行完其他操作后对环上全部进行 \(1\) 操作,这样不劣。那么图就是一棵树,如果是森林可以拆成更小的集合。对于一棵树,容易发现一条边操作的是黑白染色后颜色不同的点,那么一棵树合法的必要条件就是白点权值和等于黑点权值和,因为一次操作会同时给白点和与黑点和减 \(x\)。这个条件也是充分的,证明可以考虑钦定一个根之后剥叶子。那么只需要判断 \(S\) 是否存在子集 \(T\) 满足 \(sum_{T} = sum_{S \setminus T}\) 即可。注意 \(T,S \setminus T \neq \varnothing\)。
现在考虑原问题,一个减 \(x\) 一个减 \(x+1\) 相当于是有一个 \(\pm 1\) 的偏移量。总共 \(|S| - 1\) 次操作,相当于偏移了 \(|S| - 1\),次,那么只需要 \(\exists T, T \subset S \land T \neq \varnothing \land sum_{S \setminus T} - sum_{T} \in \{ x \thinspace \Big| -|S|+1 \leq x \leq |S| - 1 \land x \equiv |S| - 1 \pmod 2 \}\),这里同余是因为每把一个偏移量从一个集合给到另一个集合,\(\Delta\) 就会产生 \(2\) 的变化量。这样我们就可以在 \(O(3^n)\) 的时间复杂度内判断每一个集合是否可以用 \(2\) 操作变 \(0\) 了。剩下的问题相当于是选取若干合法集合,使得它们无交,求最多可以选取的集合数,这个直接 \(O(3^n)\) 枚举超集 DP 即可。
这样可能过不了。我们考虑优化一下复杂度。这里判断一个集合 \(S\) 是否合法需要 \(O(2^{|S|})\),比较慢。我们发现问题要把全集分为两个集合,所以可以考虑折半,算上排序的复杂度大概是 \(O(|S| 2^{\frac{|S|}{2}})\)。这个排序是可以去掉的,我们考虑我们已经处理了加入 \([1,i-1]\) 时所有子集和排序后的结果,新添加一个 \(i\) 相当于是把原排序结果加 \(a_i\) 与减 \(a_i\) 的所有结果排序,对于所有加 \(a_i\) 的数,它们内部顺序与上次排序的顺序一样,减 \(a_i\) 同理,所以直接把加和减的结果归并就行了。这样就是 \(O(2^{\frac{|S|}{2}}) = O((\sqrt{2} )^ {|S|})\) 的。那么总复杂度就是 \(O((\sqrt{2} + 1)^n)\) 的。
后面的 \(3^n\) 可以卡常。如果已经检查了一个 \(S\) 发现合法,那么就不用检查它的超集。这样常数会小很多。
技巧:
- 两个数的操作可以连边。
- 树上边两端的操作可以考虑黑白染色。
- 把全集分成两个子集的问题可以考虑折半。
[JOI 2025 Final] Just Long Neckties 2
首先注意到答案上限不超过 \(V\),也就是无论何时 \(B\) 中的元素都是两两不同的,因为如果有两个相同的值 \(x\),那就可以把一个数上面的 \(x\) 全部挪到另一个上面,这样其中一个不变还是 \(x\),另一个会变小,这样更优。
那么 \(B\) 的取值就只有 \(2^V\) 种情况。我们设 \(f_{i,S}\) 表示已经考虑了前 \(i\) 个人,当前 \(B\) 的取值情况为 \(S\),且最后一个回应的是 \(i\),这种状态是否可行。转移就看要不要跳过第 \(i+1\) 个人,相当于转移到 \(i+1\) 或 \(i+2\),再把对应数字填进状态里就行了。这样直接做是 \(O(n 2^V)\) 的,过不了。
状态好像记太多了,考虑精简。发现对于固定的 \(S\),满足 \(f_{i,S} = 1\) 的 \(i\) 是一段前缀。所以我们考虑记 \(g_S = \max\limits_{i=0}^{n} [f_{i,S} = 1] i\),即在 \(S\) 状态下最多可以满足前几个人。转移比较简单,当前 \(S\) 最远能满足到 \(g_S\),那么考虑在前 \(g_S\) 个数的基础上再去填 \(g_S + 1\) 或 \(g_S + 2\),然后转移到一个新的状态 \(S'\)。但是有个问题是 \(S\) 可能等于 \(S'\),即转移可能存在自环。考虑什么情况会出现自环,相当于就是你在往后走的过程中,对于 \(i\) 来说,如果 \(a_i \in S\) 或 \(a_{i+1} \in S\),那么就可以直接走过去而不改变状态。所以我们要找到 \(g_S\) 后的第一个 \(i\) 使得 \(a_i,a_{i+1} \notin S\)。我们可以考虑枚举 \(j,k \notin S\),找 \(g_S\) 后最近的二元组 \((a_i,a_{i+1}) = (j,k)\)。开 \(map\) 可以 \(O(\log n)\) 单次查询,但是我们可以做到 \(O(1)\)。我们考虑找到 \(g_S\) 后的第一个 \(j\),再在这第一个 \(j\) 后面的位置找第一个 \((j,k)\)。我们可以记 \(nxt1_{i,j}\) 表示 \(i\) 往后第一个 \(j\) 的位置,\(nxt2_{i,j} = \min\limits_{k=i}^{n-1} [a_k = a_i \land a_{k+1} = j] \thinspace k\)。这样我们就可以以 \(O(nV)\) 的复杂度预处理,\(O(V^2 2^V)\) 转移,可以通过。
技巧:
- 最优化问题可以考虑答案的值域是否较小。
- DP 复杂度爆表时可以考虑精简状态。
- 对于一些较慢的查询可以考虑预处理。
[清华集训 2024] 绝顶之战
可以看 https://www.cnblogs.com/chara-/p/19376338 。
[省选联考 2024] 重塑时光
把序列上的同一段数在图上看成一块,那么限制相当于:
- 有最多 \(k+1\) 块。
- 每块内需要按照一种可行的拓补序排列,方案数即为块的导出子图的拓补序数。
- 把每块缩成一个点,缩点之后的图也要是 DAG。
如果求出了把原图分成 \(i\) 块的方案数,那么首先操作后总共有 \(k+1\) 个位置(可能为空),那么从这里面选取 \(i\) 块非空的方案数即为 \(\binom{k+1}{i}\),然后这 \(i\) 块内部的顺序可以随意排列,再乘上 \(i!\),最后 \(k\) 刀的顺序也可以随意,再乘 \(k!\)。最终的概率就是前面的和除以总方案数 \((n+k)!\),相当于答案就是:
现在考虑怎么求 \(h\)。第一步就是求把一些点分成一块的方案数,相当于就是子图 \(S\) 的导出子图的拓补序数。这个比较典,只需要在原来的连通块上加一个 \(0\) 度点即可。设 \(dp_S\) 表示 \(S\) 的导出子图的拓补序数,那么枚举一个 \(0\) 度点,转移即为:
然后我们要对缩点后的 DAG 进行 DP。仍旧可以添加一些入度为 \(0\) 的块。此时我们添加的这些块之间两两不能有边。设 \(g_{S,i}\) 表示将集合 \(S\) 分成 \(i\) 个两两之间无边的块的方案数,转移时枚举 \(lowbit\) 所在集合 \(T\),即:
剩下的就比较套路。设 \(f_{S,i}\) 表示将 \(S\) 分成 \(i\) 块,并且组成 DAG 的方案数。转移为:
这里 \((-1)^{j+1}\) 是经典的 DAG 容斥系数,不再赘述。
现在就以 \(O(n^2 3^n)\) 的复杂度解决了问题,常熟很小,可以通过。
技巧:
- 过程较复杂的问题可以考虑一步一步求解。
- 拓补序计数可以在 \(O(n 2^n)\) 的复杂度内解决。
- DAG 计数可以考虑主旋律相关技巧(DAG 容斥)。

浙公网安备 33010602011771号