2025.1
2025.1
ARC101E
不会直接算,容斥。我们考虑钦定一些边不覆盖,这样整棵树变为一些个连通块。
这个式子中, \(|S|\) 是连通块的集合, \(x\) 是其中的一个连通块。 \(g(x)\) 显然为 \((|x| - 1) \times (|x| - 3) \times \cdots \times 3 \times 1\) ,先预处理出来。
我们再考虑上面的东西怎么算。我们发现 \(g(x)\) 只与 \(|x|\) 有关,我们设 \(f(x, i)\) 表示以 \(x\) 为根的子树的答案。其中 \(i\) 表示 \(x\) 所在的连通块大小为 \(i\) 。
考虑一条边 \(x \to y\) ,我们可以将两个连通块合并,也可以分开算贡献。
- 合并两个连通块:
- 分开算贡献,把容斥带进去算。就是给新的 \(f(y, j)\) 带上 -1 的容斥系数。因为在后面的计算中 \(y\) 对答案的贡献和 \(x\) 对答案的贡献相反。
由于以 1 为根的贡献我们没有计算,所以答案是 \(\sum f(1, i) \times g(i)\) 。
P4859
先令新的 \(k\) 变为 \(\frac{k + n}{2}\) ,现在 \(k\) 的意思变为 \(a(i) > b(i)\) 的个数。
钦定\(k\) 个 \(a(i) > b(i)\) 然后剩下乱填,记为 \(g(k)\) ,最后答案就是 \(\sum(-1) ^ {i - k}\binom{i}{k} g(i)\) 。
现在考虑如何计算 \(g(i)\) 。我们可以设 \(f(i, j)\) 表示前 \(i\) 个数让 \(j\) 个钦定满足,容易写出状态转移方程:
其中 \(pos(i) - j + 1\) 是 \(i\) 填的位置的方案数。 \(g(i) = f(n, i) \times (n - i) !\) 。
然后就做完了。
P4463
设 \(f(i, j)\) 表示选了 \(i\) 个 \(\le j\) 数的所有不合法序列的值之和。容易列出:
我们发现这个式子是若干次前缀和相加。我们猜想这个 \(f(i, *)\) 是一个关于 \(j\) 的多项式。
使用拉格朗日插值可以快速解决这个问题。现在我们只需找到这个多项式的项数就好了。
我们知道如果 \(A(x)\) 是 \(n\) 次多项式,那么 \(A(x) - A(x - 1)\) 是 \(n - 1\) 次多项式。
转化一下上面的式子,我们发现 \(f(i, j) - f(i, j - 1) = f(i - 1, j - 1) \times j\) 。
可以发现 \(f(i, *)\) 是 \(2n\) 次多项式。然后暴力转移前 \(2n +1\) 项然后拉格朗日插值就好了。
AGC030D
计数转期望然后乘 \(2^q\) 。假设每次随机交换,直接设 \(f(x, y)\) 为 \(a(x) < a(y)\) 的概率。然后每次交换两个数都相当与把两个数变为平均数。
同时的,对于 \(f(x, i) , f(y, i)\) 和 \(f(i, x) , f(i, y)\) 也要取平均。
qoj 7502
\(O(n^2)\) 想树形背包。我们发现这道题让我们强制钦定一些边走 奇/偶数 次,并且要区分入边和出边。
我们不如让子树 \(x\) 中连向 \(x\) 的入边贡献 1 ,出边贡献 -1 ,这样我们直接将两个贡献相加,能直接算出还剩多少条入边或出边,并且我们同时能很好满足钦定经过奇数次或偶数次的限制。
具体的,我们设 \(f(x, i)\) 表示以 \(x\) 为根,入边数 - 出边数为 \(i\) 的最小贡献。容易写出:
平移数组直接转移可以做到 \(O(n ^ 2)\) 。本题实现有点小细节,每个点 \(x\) 的 \(f(x, i)\) 有意义当且仅当 \(-s(x)\le i \le sum(x)\) 。其中 \(s(x)\) 是子树大小, \(sum(x)\) 是子树中可以出发的点的个数。
模拟赛 T2
先用类似标记永久化的东西把每个守望者挂到每个线段树的叶子上。然后每次查询对 \(O(\log n)\) 个答案取最大值。
现在我们只用考虑线段树上每个叶子怎么做。容易发现,我们要求的是对于时间的一串后缀的历史最大值。历史最值用 Segment Tree Beats 类似的操作维护。
对时间维护一条链,我们对每个新加进来的询问新加一个点,每次修改只在最后一个点修改。查询时查询一条链上的信息。
使用并查集路径压缩解决这个问题,时间复杂度为 \(O(n \log ^ 2 n)\) 。
ARC144D
先转化式子,变为 \(a(S) + a(T) - a(S \cap T) = a(S \cup T)\) 。
我们考虑几个相互独立的 \(S\) ,发现只要确定 \(a(2^0), a(2^1), a(2^2) ,\dots , a(2^{n - 1})\) ,剩下的都可以被算出来。同时,我们还可以给 \(a(1 \sim 2^{n - 1})\) 的数加上一个偏移量 \(a(0)\) ,上式仍然满足。
我们最后的方案数就是我们乱填 \(a(2^i)\)的情况乘上确定 \(a(2^i)\) 后 \(a(0)\) 的取值情况。
先设 \(S = \{a(2^i)\}\) ,\(a(S) = a(0) + \sum_{x\in S}a(x)\) 。所以 \(a(0)\) 的取值范围为 \([\sum_{x \in S , x < 0} x, k - \sum_{x \in S , x > 0}]\) 。总情况数 \(k + 1 - \sum_{x\in S} |x|\) 。
每个不为 0 的 \(x\) 对答案的贡献为 2 , 0 对答案的贡献为 1 。
枚举现在有 \(i\) 个非 0 的位置,乱填 \(a(2^i)\) 的情况为 \(\binom{n}{i} 2^i\) 。(先从 \(n\) 个数中选出 \(i\) 个数,每个数有正有负两种情况)
现在考虑 \(k + 1 - \sum_{x\in S} |x|\) ,的情况,相当于将 \(k + 1\) 个数中一段位置 \(t\) 给前 \(i\) 个数划分,贡献为 \(\binom{t - 1}{i - 1}\) ,剩下的 \(k + 1 - t\) 表示 \(a(0)\) 的取值情况。显然,我们可以新加一个划分的位置留给 \(a(0)\) ,总的贡献为 \(\binom{k + 1}{i + 1}\) 。
所以答案就是:
P10240
有两个限制,首先要物品数量最多,其次要字典序最大。
先用 set 维护出当前要删几个。然后目前要选一个能满足物品数量的同时编号最大的。这启发我们在元原序列上二分,这时能选择的元素是一个前缀。
我们找这个前缀中前 \(k\) 小的元素,判断合法性。这样我们就能二分出最大我们能填什么。
具体的,我们判断合法性可以在一个动态开点的权值线段树上二分出前 \(k\) 大的元素是什么。
同时,我们还要动态删除元素,所以我们可以在外面套一个树状数组,只在 \(O(\log n)\) 棵线段树上修改。
二分 + 树状数组 + 动态开点的权值线段树,总的时间复杂度为 \(O(n \log ^ 3 n)\) , \(n\) 只有 50000 ,所以可以通过。
qoj 8574
一个特例,当 \(k = 2\) 时是冒泡排序,答案为 \(0\) 。我们推广一下发现当 \(k\) 为偶数时且 \(n\ne k\) 时答案一定为 0 。
当 \(k = 4\) 时,我们可以选 \(5\) 个数手玩一下:
大概逻辑是先把 \(A,B\) 都移开,在分别把 \(A,B\) 放在对应的位置。这样就等价与 \(k = 2\) 。对于 \(k\) 为其他不为 \(n\) 的偶数时都成立。
当 \(k = 1\) 时,直接贪心模拟即可。当 \(k = n\) 时,直接 \(O(nk)\) 枚举所有情况然后沿用 \(k = 1\) 的做法即可。
最后考虑 \(k\) 为奇数的情况,我们先尽可能解决一些逆序对。继续手玩发现:
这里 \(k = 3\) ,发现我们可以交换两个位置的逆序对。所以如果逆序对数为奇数,那么答案就是对 \(a(i)\) 排序后的 \(\min \{a(i + 1) - a(i)\}\) ,如果逆序对数为偶数,那么答案为 \(0\) 。
ABC255G
考虑 \(SG(x)\) 的取值。我们发现每一个特殊限制都会导致 \(SG(x)\) 突变。
对于每个游戏,都有 \(SG(x) = \text{mex}_{i < x}{SG(i)}\) 。对于每个限制 \(x_i, y_i\) 。我们直接在 \(SG(x_i)\) 中删除 \(SG(x_i - y_i)\) 。
再发现,如果没有突变点, \(SG(x)\) 是一条斜率为 1 的直线。我们每次二分找到这个位置即可。
P5406
最大化边权没法做。我们可以直接算出权值为 \(k\) 时的答案。由于 \(n \le 70\) ,所以我们考虑矩阵树定理计数。
矩阵树定理本质上在求 \(\sum_T \prod_{e \in T} w(e)\) 。我们可以把边换为多项式。然后边和边之间用 \(FWT\) 算,这样就能求出每个答案是否合法。
所以我们先对边权 \(FWT\) ,计算矩阵的行列式,再把行列式的结果 \(IFWT\) 回来,这样就算完了。
P7450
先把问题拆开,先保证选取的块数最少,然后在此基础上找到中位数。
我们可以用 微小扰动 解决。我们二分这个中位数是什么。大于 \(mid\) 加上 \(eps\) ,反之减去 \(eps\) 。二分让扰动后的答案和原来的答案相等,最后的答案就是二分的终止位置。
再考虑如何让选取的块最少。我们设 \(f(i, j, S)\) 表示当前位置为 \(i, j\) ,颜色的集合为 \(S\) 。
我们可以列出方程使用斯坦纳树解决:
但是这样只能解决 $a(i, j) $ 比较小的情况。当元素比较多时,我们可以把它们映射到 \([0, k)\) 中,这样每次正确判断的概率为 \(\frac{k!}{k ^ k}\) 。
多随机几次就能保证正确性。这个东西叫做 color-coding 。
CF1037H
要查询一个子串在 \(s[L...R]\) 是否出现可以使用 \(SAM\) 维护 \(endpos\) 等价类实现。
对于 \(SAM\) 上的每个点,我们给它插入 \(len(i)\) ,对于 fail 树上的边,我们线段树合并子树信息就能得知所有点 \(i\) 的 \(endpos\) 等价类。
对于这道题,我们暴力匹配尽可能长的前缀,然后枚举下一位填什么然后后面不填,用 \(endpos\) 等价类判断这个字符串是否在 \([L, R]\) 中出现。
qoj 7884
先发现选一个没有什么限制的连通块不是最优的。因为每个连通块只有最大值和次大值是有用的。所以我们可以让连通块缩小为一条从最大值到次大值的链,这样做一定是不劣的。
然后我们就能设计 dp 状态,我们维护 \(x\) 连出去的链。 \(f(x)\) 表示以 \(x\) 为根的答案, \(g(x, k)\) 表示当 \(x\) 连出去的链的另一端为 \(k\) 的答案。枚举儿子节点 \(y\) ,转移是容易的。
可以线段树合并维护上面的式子。具体来说,我们可以维护当前的 \(\sum g(y')\) 和 \(\sum_{y' \ne y} g(y')\) ,每次合并时算出当前的值取 max 更新 \(g(x)\)。
qoj 9682
通过博弈论的性质,我们就是要进行若干次给某个位置加 1 的操作让所有的数异或和为 0 。
容易想到从大往小按位贪心,先满足前面的位数异或和为 0 。
假设我们现在在操作第 \(k\) 位,我们现在考虑位置 \(x\) 的数加多少。先算出不操作时异或和是多少,我们通过调整让最后的异或和为 0 。
假设我们要让当前位异或上 1 ,我们可以选择一个第 \(k\) 位为 0 的数,通过若干次操作让这一位变为 1 。
我们还可以找到两个第 k 位为 1 的数,让它们在前 \(k - 1\) 位改变相同的位置,然后将其中一个数的第 \(k\) 位变为 0 。
我们所有的情况都能通过上面的方式异或出来。但是如果直接暴搜时间复杂度会出问题。
我们考虑一步贪心,我们如果先操作对答案贡献较小的数,那么符合条件的位置就是一段前缀,后面不用考虑。
这样再去搜索时间复杂度就会和 \(m\) 取 \(\min\) ,复杂度瓶颈在于对于每一位给 \(a(x)\) 排序,总的时间复杂度为 \(O(n\log n \log V)\) 。
P6054
考虑最大流最小割定理,我们将每个选手抽象为一条链。容易发现,在这条链中有且仅有一条边被删。
我们可以把限制抽象为 \(x_i < y_i + D\) 的形式。构建一些新的链满足这个限制。
我们记 \((x, i)\) 为链 \(x\) 上的第 \(i\) 个点,我们构造一条链 \(S \to (y, i + D) \to (x, i) \to T\) ,即连边 \((y, i + D) \to (x, i)\) ,为避免隔断设流量为 \(+\inf\) 。
如果我们选择了 \(S \to (y, i + D)\) 上的边,那么由最小割的性质, \((x, i) \to T\) 上的边就一定不会被选择,所以只会选择 \(S\to (x, i - 1)\) 上的点,相当于满足限制 \(x_i < y_i + D\) 。
考虑边界情况,如果 \(D\) 为正数,那么对于 \(i + D > m\) 的点,\(x\) 可以任意取值不影响答案。但对于 \(D\) 为负数的点,当 \(y_i\) 选择的位置 \(i + D > m\) 时,\(x\) 没有位置可以选,这种情况不合法,我们考虑把这种情况去掉。
我们可以对于每条链 \(S \to (x, i) \to T\) 连一条反链 \(T \to (x, i) \to S\) 流量全部设置为 \(+\inf\) 。这样就能保证不合法的点不被选,因为还能选出一条增广路不满足条件。
这就是 广义切糕模型 ,对于这道题 \(D\) 为负数,所以我们按第二种情况建出网络流求解即可。
qoj 2441
首先选出的若干堆式子肯定构成一组线性基,否则我们可以通过线性基构造出一个数然后异或和为 0 。
现在我们需要维护如何快速处理这些信息。我们可以贪心插入每个元素,如果当前元素可以使得和更大,那么我们贪心替换这个元素。
我们还需要快速处理后缀信息,可以使用 \(SAM\) 来维护。我们统计每个点出现了多少次,就处理出这个点往后到达几个终止节点的路径数。
对于一个区间 \([l,r]\) ,我们从 \(r\) 往前倍增跳 \(father\) 即可,时间复杂度为 \(O(n \log n \log V)\) 。
uoj 938
首先最后每个树上的点都对应了原树上的某个连通块。我们可以处理出一些子树信息合并两个答案。
我们设 \(f(x)\) 是把以 \(x\) 为根的子树变为满二叉树后的树高, \(g(x)\) 是把除 \(x\) 以外的树变为满二叉树的树高。
合并是几乎一样的。对于每个节点 \(x\) ,我们考虑两个高度相同的子节点 \(f(y)\) ,如果两者相等,那么 \(f(x) = f(y) + 1\) ,否则转移就是 \(f(x) = \max_{y \in son(x)} f(y)\)。可以用各种 STL 快速合并答案。

浙公网安备 33010602011771号