NOIP 模拟T3(环上 DP,矩阵乘法,二进制分段倍增)
NOIP 模拟 T4(二分图染色)
P11057 诈骗题 蓝(二分图建模)
题意
定义 \(f(n,m)\) 为下列问题的答案。
考虑一个 \(n\times m\) 黑白网格图,初始全是白色的。每次操作如下:
- 选择一个白格子 \((x,y)\),将其所在行全染黑,这个操作叫 \((x,y,\text{R})\)。
- 选择一个白格子 \((x,y)\),将其所在列全染黑,这个操作叫 \((x,y,\text{C})\)。
假设最多能操作 \(k\) 次。问:
- 对于所有操作 \(k\) 次的方案,有多少种本质不同的 操作集合 。操作集合是一个大小为 \(k\) 的集合,代表操作过的 \(k\) 种操作。(注意,顺序不同但操作集合相同的 \(2\) 种方案只会被计算 \(1\) 次)
称两个操作集合 \(A, B\) 本质不同,当且仅当存在某种操作 \(opt\),满足 \([opt \in A] + [opt \in B] = 1\)。
现在给定 \(n,m\),请你对于所有 \(1\le i\le n,\ 1\le j\le m\) 求出 \(f(i,j)\) 的取值,取模 \(998244353\)。
保证 \(1\le n,m\le 5000\)。
题解
注意到 \(k=n+m-1\),最后一步是删掉一个 \(1\times 1\) 的矩阵。
建立行列二分图,对于操作 \((x,y)\),如果第 \(y\) 行被删除则连边 \(x\to y\),否则 \(y\to x\),显然每个点只能有一个入度。
操作后我们会得到一个外向树。
容易发现所有外向树和操作集合构成双射,因此答案为 \(K_{n,m}\) 的有根生成树个数,这是一个经典结论,答案为 \((n+m)\times n^{m-1}\times m^{n-1}\)。
提交记录
P11056 Fire and Big 蓝(博弈论,打表)
题意
小 F 要和其他人玩游戏,但他不想输,所以来找你帮他研究策略。
有 \(m\) 个石子,小 F 和小 B 轮流取石子,小 F 先开始取,不能取的人输。
给定正整数 \(n\),每次取石子的个数 \(k\)(\(k\) 是正整数) 必须满足如下两个条件之一:
- \(k\) 是 \(n\) 的倍数。
- \(k\) 是 \(<n\) 的完全平方数。
他们要玩 \(T\) 局游戏,不过每一局游戏的 \(n\) 不变,只有石子个数 \(m\) 会变。
对于每一局,假设两人足够聪明,问谁有必胜策略。
对于所有数据,保证 \(1\le T,n\le 5\times 10^5\),\(1\le m\le 10^9\)。
题解
打个表发现后手必胜个数极少。
发现如果把模 \(n\) 相同的数看作一个等价类,每个类里面只能有一个后手必胜,这是显然的。
因此直接往后递推,遇到后手必败就更新后 \(\sqrt n\) 个状态,这样总状态数 \(O(n\sqrt n)\),可以接受。
提交记录
[AGC002E] Candy Piles 紫(二维平面,博弈论)
题意
桌子上有 \(N\) 堆糖果。每堆糖果有 \(a_i\) 颗糖果。
Snuke 和 Ciel 正在玩游戏。他们轮流走。Snuke 先走。在每个回合中,当前玩家必须执行以下两个操作之一:
- 选择剩余糖果数量最多的一堆,然后吃掉那堆糖果中的所有糖果。
- 从仍有糖果剩余的每堆中吃一颗糖果。
吃了桌上最后一块糖的玩家输掉了比赛。确定如果两个玩家都以最佳方式玩游戏,哪个玩家会赢。
\(N\leq 10^5\)。
题解
将糖果从大到小排序,放到二维平面上考虑,在二维平面上有一个直方图,每次往上或往右,走到边界算输。
关键结论:在网格图上,不考虑边界问题的情况下,\((x,y)\) 和 \((x+1,y+1)\) 的胜负态一样。证明是简单的,反证法即可导出矛盾。
因此直接从 \((0,0)\) 走到最后一个不是边界的点,然后先手现在要么往右要么往上,之后操作方案唯一,判一下奇偶性即可。
提交记录
[AGC002F] Leftmost Ball 紫(计数)
题意
Snuke 喜欢彩色球。他共有 \(N\times K\) 个球,其中包含 \(N\) 种他最喜欢的颜色,每种颜色各有 \(K\) 个。颜色编号为 \(1\) 至 \(N\)。
他将所有球从左到右排成一行,顺序任意。然后,对于每种颜色,他会将该颜色最左侧的球重新涂为颜色 \(0\)(这是一种不同于原有 \(N\) 种颜色的新颜色)。
涂色完成后,球的颜色序列可能有多少种不同的排列方式?请将答案对 \(10^9+7\) 取模。
\(1\leq N,K\leq 2000\)。
题解
白球对其他球的限制是:任意后缀(或前缀)的白球个数大于等于颜色种类数。
只限制后缀也能保证正确性,因此从后往前 DP,并且需要把白球个数和颜色种类数计入状态。
具体地,我们钦定 \(i\) 第二次出现的位置小于 \(i+1\) 第二次出现的位置。
令 \(dp_{i,j}\) 表示填入了 \(i\sim n\) 的数字,填入了 \(j\) 个白球的方案数,每次钦定填入的第一个球在最前面以避免重复。
转移是简单的。
似乎也可以正着做。
提交记录
[AGC001F] Wide Swap 黑
题意
给定一个长度为 \(N\) 的数列 \(P_1\ldots P_N\),该数列是 \(1\sim N\) 的一个排列。
你可以对该数列进行如下操作任意次:
- 选择整数 \(i, j\),满足 \(1 \leq i < j \leq N\)。
- 交换 \(P_i\) 和 \(P_j\) 的值。
- 但必须满足 \(j - i \geq K\) 且 \(|P_i - P_j| = 1\)。
请你求出通过上述操作能够得到的字典序最小的数列。
\(2\leq N\leq 500000\)。
题解
下标差大于 \(K\) 且值相邻不好处理,这种情况可以考虑将排列转为逆排列,变为交换相邻且值相差超过 \(K\) 的值。
从前往后扫,再从后往前冒泡,即可做到 \(O(N^2)\)。
使用平衡树模拟冒泡过程,二分一个位置能冒泡到哪,可以做到单 \(\log\),但是比较麻烦。
这个东西是冒泡排序形式,考虑使用高级排序算法进行优化。
首先冒泡的条件是 \(q_{i-1}\geq q_i+k\),因为交换顺序对显然不优,使用归并排序,记录归并第一段的后缀 \(\min\) 即可判断是否可以进行归并。
另一个做法是按照值域连边然后拓扑排序,通过分析边之间的支配关系将边数缩小到 \(O(N)\)。
提交记录
P9818 游戏王 紫(knapsack 技巧)
题意
给出一个长为 \(n\) 的序列 \(\{S_n\}\),其中 \(S_i\) 为多个二元组 \((s_{i,j},m_{i,j})\) 构成的可重集。有 \(q\) 次询问,每次给定 \(l,r\),你需要从 \(S_l,S_{l+1},\cdots,S_r\) 的每个集合中分别选出 \(0\) 个或 \(1\) 个二元组。记选出的 \(k\) 个二元组为 \((s'_i,m'_i),1\le i\le k\),则你需要在保证 \(\prod_{i=1}^km'_i\le v\) 的基础上,最大化 \(\sum_{i=1}^k s'_i\)。
对于所有数据,保证 \(1\le n,tot\le 10^5\),\(1\le q\le 2\times 10^5\),\(1\le m_{i,j}\le v\le 10^5\),\(1\le s_{i,j}\le 10^4\),\(1\le l\le r\le n\)。
题解
直接 DP 是不弱于背包的,无法优化。
Hint:对于乘积小于某个数的背包,可以整除分块做到 \(O(\sqrt V)\) 状态。
具体地,将 \(\frac{V}{\prod m}\) 计入状态,因为 \(\frac{\frac{x}{y}}{z}=\frac{x}{yz}\),因此状态是可合并的。
前缀和优化后可以 \(O(\sqrt V)\) 的求出一个位置的值,用类似猫树的结构分治即可。
提交记录
NOIP 模拟 T3(计数,随机选数转排列,树上 DP)
题意
考虑这样的一个算法:
给定树 \(T\),初始时图上所有节点均为白色,计数器 \(c = 0\)。不断进行下列操作直到 \(T\) 上不存在白色点:
- 从树上所有白色点中随机选择一个点 \(u\),将 \(u\) 以及与其有边直接相连的所有白色点 \(v\) 全部染黑,并令 \(c \leftarrow c + 1\)。
最后返回 \(c\) 作为答案。
林尼想知道,对于给定的树 \(T\),算法的正确率是多少,即有多大概率使得算法返回的答案确实为原图的最大独立集大小。
你只需要输出概率对 \(10 ^ 9 + 7\) 取模的结果。
记 \(n\) 为树的大小,\(n\leq 5000\)。
部分分:最大独立集唯一。
题解
首先按照经典套路,将白点选数改成随机一个排列,按排列选数,然后跳过不合法的选择。
这样最终方案和排列构成双射,至此我们完成了概率转计数。
考虑部分分,分析排列性质,首先考虑限制所有独立集的点都被选,但是发现这样不好限制。
考虑限制所有不在独立集的点都不被选,由于是独立集,所以这样限制也是充要的。
记排列的逆为 \(rk\),独立集为 \(S\)。一个不是 \(S\) 的点 \(u\) 不被选,当且仅当存在一个邻域 \(v\),\(rk_v<rk_u\),且 \(v\in S\),这样我们就得到了充要条件。
记 \(f_{u,i,0/1}\) 表示子树 \(u\) 内,离散化后的 \(rk_u=i\),且如果 \(u\notin S\),是否有 \(u\) 的儿子 \(v\),满足 \(v\in S\land rk_v<rk_u\)。
转移时如果 \(u\in S\),则直接合并 \(f_{v,x,1}\),对于 \(f_{v,x,0}\),我们需要做的问题如下:
- 合并两个数列,第一个序列的第 \(x\) 个位置在第二个序列的第 \(y\) 个位置前。
转移时进行树上背包:
如果 \(u\notin S\),大致同理,当第三维由 \(0\) 变 \(1\) 时做上面的转移,只是把 \(>\) 改为 \(\leq\)。
可以前缀和优化做到 \(O(n^2)\)。
考虑正解。
类似 DP of DP,先使用最大独立集 DP(\(g_{u,0/1}\) 表示 \(u\) 子树 \(u\) 是否选择)建立出最优转移 DAG,然后在 \(f\) 后加一维表示 \(u\) 是否属于 \(S\),只进行 DAG 上边的转移即可。
我们无需显式建立 DAG,只需要在往上做独立集 DP 时只转移最优情况即可。
NOIP 模拟 T4(构造,杨表)
题意
给定一个数 \(n \geq 3\),你需要构造一颗树,其中每个点有正整数点权,满足:
- 对于任意一个 \(k \in [1,n]\),满足存在一条点数 \(> 1\) 的链,使得链上点的 \(\gcd = k\)。
由于一些原因,你希望树的点数与权值尽可能小。具体来说,每个点有一个限制 \(X,Y\),你需要保证你构造的树的点数 \(\leq X\),且你构造的树的点权 \(\max \leq Y\),你通过这个点。
\(n\leq 2500,X=n,Y=11000\)。
部分分:\(X=\frac{3n}{2}\)。
题解
考虑部分分,先构造一个 \(2n\) 个点的方案,然后把互成倍数的点合并到一条链上。
现在我们只用到了 \(2\),考虑继续用 \(3\)。我们引入一个科技:
- 有一个表格叫做杨表,其中 \((x,y)\) 位置的值时 \(2^x\times 3^y\times a\),\(a\) 是与 \(6\) 互质的任意数。
这个表格的性质是任意一条链的 \(\gcd\) 是其横纵坐标 \(\min\) 所对应的点,因此我们枚举 \(a\) 建立杨表,把杨表中大于 \(n\) 的数所围成的路径连接起来,构成一条链,就实现了 \(X=n+w\),\(w\) 是极小的常数(这个是暴力验证的)
然后开始发癫,把两个大于 \(\frac{n}{2}\) 的值单独处理,不使用杨表,对于两个大于 \(\frac{n}{2}\) 且与 \(6\) 互质的数 \(x,y\),构造 \(x-\text{lcm}(x,y)-y\) 的链,即可省去一个点,可以通过。
事实上只需要配对一组 \(x,y\) 就能过了,😓。
P7013 [CERC2013] History course 黑(数据结构优化贪心,Hall 定理,单调性)
题意
你需要按某种顺序为一系列重要历史事件安排讲座,每个讲座对应一个事件。每个事件持续一段时间区间 \([a_i, b_i]\)。如果两个事件的时间区间有公共点,则称这两个事件是相关的。为了方便起见,安排相关事件的讲座时应尽量靠近。此外,对于不相关的事件,讲座应按照事件发生的顺序进行(如果事件 A 先于不相关事件 \(B\) 发生,那么 A 的讲座应先于 B 的讲座)。找到最小的整数 \(k \ge 0\) 和一个讲座顺序,使得任何两个相关事件的讲座之间的间隔最多为 \(k\)(讲座编号 \(i\) 和 \(j\) 之间的间隔被认为是 \(|i−j|\))。
\(n\leq 50000\)。
题解
先二分答案,然后尝试构造。
一个 \(k=mid\) 的方案的合法判据是,对于任意区间 \(i\),若 \(i\) 填入第 \(j\) 个位置,与其相交的区间填入位置 \(\leq j+mid\)。
我们不好处理相交,但是题目有一个神秘要求:相离的区间 \(l\) 小的排前面。我们发现这个限制对答案没有任何影响,但是可以给我们一些提示。
具体地,我们考虑弱化相交条件,将 \(l'<r\land r'>l\) 弱化为 \(l'<r\),这样由于题目的神秘要求,判据仍然成立。
做到这,大致思路就出来了,按 \(r\) 贪心从小到大填入,同时维护每个区间的最大位置。
具体地,令 \(f_i\) 表示第 \(i\) 个区间的最大位置,初始时 \(f_i=n\)。按照课程顺序填入区间,填入第 \(i\) 个区间 \([l,r]\) 时将与其相交的区间的 \(f\) 对 \(i+mid\) 取 \(\min\)。
这是我们注意到:将区间按 \(l\) 排序后,\(f\) 为前缀 \(chkmin\),且由于 \(i+mid\) 递增,每个 \(f\) 只会被 \(chkmin\) 一次,十分优美。
当然区间不能随便填,显然我们的 \(f\) 限制对当前局面是必要的,当我们不知道限制的时候,先考虑对于一个 \(f\) 如何判无解。
一个显然的思路是,将 \(i\) 与 \(1\sim f_i\) 连边,转为二分图最大匹配,之后用 Hall 定理作为判据。
具体地,令 \(s_i=\sum\limits_{x} [f_x=i]\),并且规定已经填入的区间的 \(f\) 值为 \(0\)。
记 \(use(l,r)\) 表示当前位置 \([l,r]\) 中已经有区间占用的位置个数。如果存在 \([l,r]\) 满足 \(\sum\limits_{i=l}^{r} s_i< r-l+1-use(l,r)\),则无解,我们需要在贪心时尽可能避免这种情况。
记 \(c(l,r)=r-l+1-use(l,r)-\sum\limits_{j=l}^{r} s_j\)。
具体地,利用增量构造的思想,假设无解判据中 \(l=1\sim i\) 的情况已经满足,且我们在填入 \(i\) 时只能避免上述无解判据中 \(l=i+1\) 的情况,且对于任意 \(r\),我们有能力保持 \(c(i,r)\) 不变。构造方式是选一个 \(f\in [i,r]\) 的区间填入当前位置。
因此我们声称,只有存在一个 \(r\) 满足 \(c(i,r)=0\) 时我们才需要对操作进行限制,要不然我们完全不用着急,只需要等待其变为 \(0\) 后让其保持即可。
具体地,我们找出最小的 \(r\) 满足 \(c(i,r)=0\),然后在 \(f\in [i,r]\) 的点中找到 \(r\) 最小的填入当前位置。
进一步把 \(f\in [i,r]\) 改为 \(f\leq r\),因为填到 \(i\) 时必有 \(f_x\geq i\ \ (x\geq i)\),否则不符合“最后位置”的定义。
由于 \(i+mid\) 递增,每个 \(f\) 只会被 \(chkmin\) 一次,因此我们可以双指针维护 \(f\),并实时维护 \(s\),并且在线段树上的一个原区间 \([l,r]\) 维护 \(c(l,r)\) 和 \(\min_{l\leq i\leq r} c(l,i)\),这一部分是容易的。
我们再维护一颗线段树维护一个区间内 \(r\) 最小的区间编号。
我们二分出最前的 \(r\) 满足 \(c(i,r)=0\),然后在 \(f\leq r\) 的区间中找到 \(r\) 最小的区间填入,最后更新 \(f\) 和维护 \(cost\) 的线段树。
我们额外维护 \(g_i\) 表示 \(\max\limits_{x} f_x=i\),以实现 \(f\) 值域和区间编号的转化。
提交记录
P8147 [JRKSJ R4] Salieri 黑(ACAM,树上差分,虚树)
题意
给出 \(n\) 个字符串 \(s_i\),每个字符串有一个权值 \(v_i\)。\(m\) 次询问每次给出一个字符串 \(S\) 和一个常数 \(k\)。设 \(cnt_i\) 为 \(s_i\) 在 \(S\) 中的出现次数,求 \(cnt_i\times v_i\) 第 \(k\) 大的值。
对于 \(100\%\) 的数据,\(1\le n,m\le10^5\),\(\sum |S|,\sum s_i\leq 5\times10^5\)。
\(s\) 和 \(S\) 中只会出现 \(\texttt a,\texttt b,\texttt c,\texttt d\) 四种字符,\(v_i\le10^3\),\(k\le n\)。
题解
死因:认为 \(s_i\) 的每个位置在 ACAM 上都有贡献。
该复习一下 ACAM 了。
多模匹配,有两种思路:ACAM 和 SA(M)。
考虑 SA,可以将问题转化为:
- 给定一个长为 \(O(L)\) 的序列,每个位置有一个值和一个颜色,颜色范围为 \([1,n]\),多次询问一个区间 \([l,r]\),记 \(sum_x\) 表示区间内颜色为 \(x\) 的位置的值的和,求 \(sum\) 序列的第 \(k\) 大。
这个东西的信息量是平方的,问了 GPT 得知复杂度下界为 \(O(n^{1+\epsilon})\),所以这个做法似了。
Hint:通过 ACAM 将一个字符串转为只有一个点有贡献,可以解决很多棘手的多模匹配问题。
考虑 ACAM,如果用 \(S\) 建立 ACAM,会转化为和上述问题类似的问题,这里不再赘述。
用 \(s_i\) 建立 ACAM,记 \(p_i\) 表示 \(s_i\) 的结束位置,把 \(S\) 在 ACAM 上跑一遍得到点集 \(T\),\(s_i\) 在 \(S\) 中出现,当且仅当存在 \(x\in T\),\(x\in \text{subtree}(p_i)\)。这样,每个 \(s_i\) 提供的有用位置恰好是 \(1\) 个,比上面的问题优美很多,而且信息量是对的。
对 fail 树树剖,对 \(T\) 上每个点实现到根链加,可以将问题转化为:
- 维护一个序列,每个位置有一个值 \(v_i\) 和一个值 \(t_i\),实现区间 \(t_i\) 加,全局求 \(v_i\times t_i\) 的第 \(k\) 大,询问在查询后。
先二分答案,转化问求 \(v_i\times t_i\geq mid\) 的位置个数,由于区间加一共 \(O(|S|\log S)\) 次,因此不同的 \(t\) 一共 \(O(|S|\log S)\) 个,之后对一段相同的 \(t\),用主席树查 \(v_i\geq \lceil \frac{mid}{t} \rceil\) 的个数即可,维护到根连主席树,每次二分有 \(O(|S|\log S)\) 次主席树查询,一共三 \(\log\),无法通过。
你发现你学树剖学傻了,重新分析 \(T\) 的到根连加法,发现 \(T\) 的点构成一颗虚树,虚树上只有 \(O(|S|)\) 条边,于是复杂度双 \(\log\),因为 \(v\leq 10^3\),不用担心主席树常数和空间问题,做完了。
提交记录
P13559 【MX-X15-T6】翻树树 蓝(构造)
题意
小 G 有一棵 \(n\) 个节点的树,节点的编号为 \(1 \sim n\)。每个节点的颜色可以是黑或者白,初始所有节点都为白色。
小 G 和小 C 还各有一个集合,分别称作 \(S\) 和 \(T\)。\(S\) 为所有节点的度数组成的集合,而初始时 \(T = \varnothing\)。
小 C 可以进行若干次操作。在每次操作中,他可以翻转树上的一个节点的颜色(黑变白、白变黑)。随后,他会计算 \(k\) 为树中两端点不同色的边数,然后将 \(k\) 插入至集合 \(T\) 中。
小 G 指定了一个整数 \(m\),满足 \(m \geq 2\lceil\sqrt{n}\rceil\)。如果小 C 使用了超过 \(m\) 次操作,小 G 就会生气。小 C 被要求在小 G 不生气的情况下让 \(T \supseteq S\),可他并不会解决这个问题。你能帮他构造一组方案吗?
题解
Hint:叶子个数 \(\geq\) 节点度数最大值。
考虑暴力,最多有 \(\sqrt {2n}\) 个不同的度数,每个度数找一个点翻两次,次数为 \(2\sqrt {2n}\)。
考虑更多的暴力,把所有叶子翻一次,次数为 \(\max\limits_{1\leq i\leq n} deg_i\)
考虑使用翻转叶子来平衡,具体地,设定阈值 \(B\),度数大于 \(B\) 的点翻两次,再翻 \(B\) 个叶子。
证明:
能使得操作次数最大的 \(S=\{1,3,5,\dots B-1,B,B+2,B+4,\dots,B+2k\}\),这样保证 \(B\) 是最优的,解 \(\sum_{i\in S} (i-1)\leq n-2\)(\(n-2\) 是因为至少有两个叶子,去重后和只会变小),得到 \(B+2k\) 的最大值 \(\leq 2\lceil\sqrt{n}\rceil\)。
提交记录
CF1466H Finding satisfactory solutions *3300
题意
有 \(n\) 个人,第 \(i\) 个人初始的时候手上有物品 \(i\)。
他们之间可以交换物品,每个人恰好拿到一个物品。而每个人有对物品的偏好,第 \(i\) 个人的偏好用排列 \(\{s_{i,n}\}\) 来表示。第 \(i\) 个人相较物品 \(y\) 更喜欢物品 \(x\),当且仅当在排列 \(\{s_{i,n}\}\) 中 \(x\) 在 \(y\) 之前。
对于一个物品交换的排列 \(p\),表示第 \(i\) 个物品最后到了 \(p_i\) 的手上。对于一个非空的,人的子集 \(S\),如果子集内部的人,使用子集内所有人初始手上的物品进行交换,可以达到以下结果:
-
不存在一个人 \(x \in S\),在子集内交换后得到物品 \(y \in S\),且第 \(x\) 个人比起 \(y\) 更喜欢 \(p_x\)。
-
至少存在一个人 \(x \in S\),在子集内交换后得到物品 \(y \in S\),且第 \(x\) 个人比起 \(p_x\) 更喜欢 \(y\)。
则称这样一个子集 \(S\) 是“不稳定”的。一个物品交换的排列 \(p\) 是“稳定”的,当且仅当不存在一个“不稳定”的子集。
现给出一个物品交换的排列 \(p\),求有多少种 \(\{\{s_{1,n}\},\{s_{2,n}\}\cdots,\{s_{n,n}\}\}\) 使得 \(p\) 是“稳定的”。
可以证明,对于一组 \(\{\{s_{1,n}\},\{s_{2,n}\}\cdots,\{s_{n,n}\}\}\),恰好存在一个 \(p\) 是“稳定”的。
\(1 \leq n \leq 40\)。
题解
一开始读题读成选出的集合必须封闭,白做了 1.5h。
考虑题目给出的判据。
- 使用子集内所有人初始手上的物品进行交换,说明交换后的集合是一个若干个置换环的并。
- 不存在一个人 \(x \in S\),在子集内交换后得到物品 \(y \in S\),且第 \(x\) 个人比起 \(y\) 更喜欢 \(p_x\)。至少存在一个人 \(x \in S\),在子集内交换后得到物品 \(y \in S\),且第 \(x\) 个人比起 \(p_x\) 更喜欢 \(y\)。以某种方式重排置换环后,不会存在每个人都不劣的情况。
题目说:可以证明,对于一组 \(\{\{s_{1,n}\},\{s_{2,n}\}\cdots,\{s_{n,n}\}\}\),恰好存在一个 \(p\) 是“稳定”的,我们尝试证明这一点。
考虑模拟题目的调整法,先令 \(i\to s_{i,1}\),然后调整。
此时,置换图是一个基环内向树森林,对于一个环,如果令 \(S\) 为这个环上的点,则这些点只有一种方案,即当前的最优方案,因此这个环已经确定。
将环删去,剩余点如果指向环,则把边指向 \(s_{i,2}\),然后递归下去即可。
这样我们每一步都是固定且最优的,连环一起被删除的边就是最终的 \(p\),证毕
考虑被删除的边满足的性质,若 \(j\) 在 \(\{s_i\}\) 中排名比 \(p_i\) 靠前,则必有 \(i\to p_i\) 被删除。
分析被删除的边的性质,显然被删除的边不能成环,具体地:
连白色边 \(i\to p_i\),连黑色边 \(i\to j\ \ (rk(s_i)_j<rk(s_i)_{p_i})\),则每个环中不能有黑边。
必要性显然,充分性可以通过构造 \(p\) 的方法证明,只要黑边都不在环内则黑边必定被删。
感性理解就是选择红色集合重排。


将置换环缩点,黑边连成若干个 DAG,考虑 DAG DP。
先考虑对于一个 DAG 如何统计答案。
我们并不关心黑边的顺序,如果 \(i\) 连出了 \(deg_i\) 条黑边,则对答案的贡献就是 \((deg_i)!(n-deg_i-1)!\)。
令 \(dp_S\) 表示集合 \(S\) 连成 DAG 的答案,\(E(X,Y)\) 表示集合 \(X\) 向集合 \(Y\) 的所有边方式的答案之和,则有:
DAG 计数只能指数级 DP,这个 DP 没有任何优化前途,但是由于我们对置换环缩点,因此这个 DP 的状态数看起来不多。
现在我们需要求 \(E(X,Y)\),从对答案贡献来看,每个点是独立的,即 \(E(X,Y)=E(\{x\},Y)^{|X|}\ \ (x\notin Y)\)。
单点连向 \(Y\) 的贡献,可以枚举这个点的 \(deg\),即 \(\sum\limits_{i=0}^{|Y|} \binom{|Y|}{i}i!(n-i-1)!\)。记其为 \(g(|Y|)\)。
受求 \(E(X,Y)\) 过程的启发,我们不关心点的编号,只关心环的大小。将 DP 状态 \(S\) 改为每个大小的环出现了几次,爆搜总状态数,发现最多只有 \(1440\) 种状态,状态的平方都是可接受的,无需任何优化。
则:
其中,\(sz_S\) 表示 \(S\) 中原图上的点数,\(loop_S\) 表示 \(S\) 中缩点后的点数,即置换环数。\(in(T,S)\) 表示 \(S\) 包含 \(T\),\(X(S,T)\) 表示从 \(S\) 中选出状态为 \(T\) 的子集的方案数。
提交记录
CF1770F Koxia and Sequence *3100(观察性质,容斥,Lucas 定理,范德蒙德卷积,拆位技巧)
题意
Mari 有三个整数 \(n\)、\(x\) 和 \(y\)。
如果一个长度为 \(n\) 的非负整数数组 \(a\) 满足以下条件,则称其为“好数组”:
- \(a_1 + a_2 + \ldots + a_n = x\);
- \(a_1 \mid a_2 \mid \ldots \mid a_n = y\)。
一个好数组的得分定义为 \(a_1 \oplus a_2 \oplus \ldots \oplus a_n\)。
Koxia 想让你求出所有好数组得分的总异或值。
题解
看到这道题首先思考题目限制条件,\(y\) 的第 \(i\) 位为 \(0\) 表示不用填入数字,为 \(1\) 表示要填入一个数字。
题目还要求和为 \(n\),有两个思路,一个是对按位或为 \(y\) 容斥,一个是数位 DP。
感觉容斥不好做,考虑数位 DP,按位分配,令 \(f_{i,j}\) 表示只考虑低 \(i\) 位,向 \(i+1\) 位进位为 \(j\) 的所有数组异或和,\(g\) 表示方案数,有转移
复杂度 \(O(y^2\log n)\),不可接受。
根据 Lucas 定理有:
感觉还是没法优化呜呜。
看题解,怎么真是容斥,怎么第一步就错了/ll。
每个位置是独立的,因此对于每个位置,其等于任意值的情况都相等,因此 \(n\) 是偶数时答案为 \(0\),\(n\) 是奇数时答案为所有序列 \(a_1\) 的异或和。
需要意识到:
- 要直接处理和为 \(n\) 且异或和为 \(y\) 必须数位 DP。
- 数位 DP 复杂度至少 \(O(y^2)\)。
我们不能直接维护两个信息,考虑对异或和为 \(y\) 容斥。
记 \(ans(y')\) 表示钦定 \(\forall_{i} ,a_i\subseteq y'\) 的答案,子集反演,此时容斥系数要么为 \(1\) 要么为 \(-1\),对异或和都有贡献。
因此答案直接异或起来就是对的,为
拆位求 \(a_1\),规定 \(a\) 的某一位必选并提前去掉这一位,\(a_1\) 的第 \(i\) 为贡献为:
根据上面数位 DP 用到的 Lucas 定理,我们知道 \([x\subseteq y]=\binom{y}{x}\bmod 2\)。
上式的 \(\sum a\) 固定,如果逆用 Lucas 定理,可以套用范德蒙德卷积公式。
枚举 \(i,y'\),时间复杂度 \(O(y\log y)\)。
提交记录
P3665 [USACO17OPEN] Switch Grass P 紫(MST)
题意
给定一张图,每个点有一个颜色,实现数据结构维护:
- 颜色单点修改。
- 全局查询异色边边权最小值。
题解
根号分治是没有前途的。
Hint:如果 \(a\) 和 \(b\) 颜色不同,则中间必有一条边是异色边,选边权最小的异色边贡献到答案。
所以异色边的支配关系满足最小瓶颈路的支配关系,只需保留在 MST 上的 \(n-1\) 条边,然后就随便做了。
这道题启示我们可以使用 MST 很好的刻画边的支配关系。
(不小心把 mid>=pos 打成 mid>=l 了,我是奶龙。
提交记录
有另一个优美的做法,建立 Kruskal 重构树,对于一个虚点,当以下条件满足时,他可能成为答案:
- 两侧子树内颜色相同
- 两侧子树间颜色不同
且不满足第一个条件不会让答案边优。
因此子树内任何一个点的颜色都能代表整个子树,把 Kruskal 重构树建为链,具体地,在连边时将链头和链尾连接,链上找边权最小的异色边即可。
暴力维护的复杂度就是对的。
P13004 [GCJ 2022 Finals] Schrödinger and Pavlov 紫(计数转期望,模拟)
题意
给定 \(n\) 个节点,已知每个节点上的状态是「确定有猫」「确定没有猫」「不确定是否有猫」三种状态之一。
对于节点 \(i\),它唯一的一条出边为 \(i \to a_i (i \neq a_i)\)。
现在遍历节点 \(i = 1, 2, \cdots, n\),若节点 \(i\) 有猫,且节点 \(a_i\) 无猫,则位于节点 \(i\) 的猫移动到节点 \(a_i\)。同一只猫在整个过程中可能会多次移动。
设初始有 \(k\) 个位置的状态为「不确定是否有猫」,则对于所有节点,有 \(2^k\) 种可能的初始猫分布的状态。
求遍历完后,节点 \(n\) 有猫的可能初始状态数量。对 \(10^9 + 7\) 取模。
\(1 \leq a_i \leq n \leq 5000\),多测,\(\sum n\leq 6170000\)。
题解
第一反应是考虑基环树上 DP,发现根本做不了。
考虑计数转期望,令 \(f_i\) 表示 \(i\) 有猫的概率,直接按题意模拟过程。
当然,这是错的,因为有环,环上点概率不独立,无法相乘。
因为这是基环树,有两种处理方法:
- 断一条边。
- 环上 DP。
无论如何都需要规定一个起始点。
考虑枚举第一步,断开环上编号最小的点的出边 \(x\to a_x\),枚举 \(x,a_x\in \{0,1\}\) 四种状态,就做完了。
断开最小的点的出边是因为,先执行第一步后剩余的图构成 DAG,对于未转移到的点,点之间概率是独立的。
还有一个更“符合直觉”的想法是断开编号最小的入边,但是这样是没有任何道理的,因为模拟到最后边的两侧不独立且无法被直接规定为有猫/无猫。
简单来说,每次执行操作 \(i\) 时,需要保证要么 \(a_i\) 这个点状态完全确定,要么 \(a_i\) 这个点状态完全不确定(即概率为 \(\frac{1}{2}\))。
具体地,在模拟到 \(x\) 时,乘上 \(x\) 和 \(a_x\) 处于被规定状态的概率,并将 \(x,a_x\) 修改为我们规定的状态。
注意我们规定的是执行 \(x\) 时的状态,因此规定 \(x\) 有猫并不代表它在初始状态可能有猫。
复杂度 \(O(Tn)\)。
这道题启示我们:
- 概率 DP 时破环成链也是正确的,即转移成环时可以枚举第一步的状态。
- 在转移构成一条链的概率 DP 中可以任意选择一个 DP 状态并固定其值为 \(p\),并对最后算出的结果乘上它值为 \(p\) 的概率计入答案。
提交记录
NOIP 模拟 T1 (Ad-hoc,构造)
题意
小 M 马上要闯一个传送阵,这个传送阵由 \(K+1\) 排房间组成,每排有 \(N\) 个房间。第 \(i(i \le K)\) 排房间与第 \(i+1\) 排房间间有传送门连接,其中对于 \(\forall i \le K\) 都存在一个长为 \(N\) 的排列 \(P_i\) 满足第 \(i\) 行第 \(j\) 个房间与第 \(i+1\) 行第 \(P_{i,j}\) 个房间间有传送阵连接,在闯关过程中可以将排列 \(P_i\) 变为 \({P_i}^{-1}\),也就是让第 \(i\) 行第 \(P_{i,j}\) 个房间与第 \(i+1\) 行第 \(j\) 个房间连接。
小 M 初始在第 \(1\) 行的某个房间,每次只能向编号更大的行走,一直要走到第 \(K+1\) 行的某个房间。
现在你并不知道他初始会在哪个房间,目标在哪个房间,请你设计这 \(K\) 个排列,使无论初始在哪个房间,目标在个房间,小 M 都可能完成闯关。
题解
倍增 shift,发现只能过 \(n\) 是奇数,因为 \(n\) 是偶数奇偶性不对。
考虑分治,难点在于合并区间,合并条件是每一个点既能到这一侧又能到另一侧。
Hint:遇到这种问题,尝试考虑特殊情况和小情况,用小数据情况拼成大数据情况。
每次从两边各拿出两个点,发现这四个点可以合并。
边界情况是每次从两边各拿出三个点,此时一个排列做不到,新加一个排列即可。
选三个点的情况是两个 \(n=6\) 的排列,可以暴搜也可以手搓,手搓方法是第一个排列满足 \(4\) 个点,第二个排列满足 \(4\) 个点,保证每个点被满足至少一次。
NOIP 模拟 T2(位运算)
题意
给定一个正整数 \(k\) 和一个长为 \(n\) 的数组 \(\left \{ a \right \}\),保证对于 \(\forall 1 \le i \le n\),都有 \(0 \leq a_i < 2^{k}\),且对于 \(\forall 1 \le i < n\),都有 \(a_i \le a_{i+1}\)。
定义如下函数:
你需要求出 \(\sum \limits _{x=0}^{2^{k}-1} f(n,x)\) 和 \(\sum \limits _{x=0}^{2^{k}-1} g(n,x)\) 的值,答案对 \(2^{64}\) 取模。
题解
首先放 Trie 树上模拟一下即可发现只有 \(a_n\) 能取到最大值。
所以第一问直接令 \(x \oplus a_n=2^k-1\)。
考虑按位递推,令 \(f_i\) 表示只考虑 \(a_n\) 低 \(i\) 位的值,容易得到递推式。
考虑求 \(\sum g\)。
显然,如果 \(a_i\) 能取到最大值,则比 \(a_i\) 大的数字也能取到最大值。
设当前最大值为 \(ans\),则 \(x\oplus a_i=ans\),由前缀最大性质,易证 \(x\subseteq ans\),则若要使 \(a_i\) 最小,必有 \(a_i=ans\oplus x\)。
枚举 \(x\) 从高到低第一个和 \(a_n\) 相同的位置。
如果这个位置的值是 \(0\),无法确定 \(ans\),我们把问题缩小到了子问题,但是贡献计算涉及到值平移,因此我们似乎啥也没干。
如果这一位是 \(1\),则 \(ans\) 的后若干位都是 \(1\) 很好做。
因此我们打破套路,枚举第一位相同且为 \(1\) 的位置。
对于前面的位置,\(a_n\) 这一位为 \(0\) 时 \(x\) 任意,\(a_n\) 这一位为 \(1\) 时 \(x\) 这一位为 \(0\),否则与“第一个相同且为 \(1\) 的位置”矛盾,记前面位置的方案数为 \(2^{cnt0}\)。
则 \(ans\) 低位取全 \(1\),\(x\) 低位任取,根据异或的经典双射结论,\(ans\oplus x=000\dots 000\sim 011\dots 111\) 。
则令 \(l=\min ans\oplus x,r=\max ans\oplus x\),贡献为 \(2^{cnt0}\times \sum\limits_{i=l}^{r} \sum\limits_{j}[a_j\geq i]\),随便拆一下贡献就行了。
要处理 \(a_n\) 和 \(x\) 每一位都不同的情况,这种情况很好处理。
NOIP 模拟 T3(多项式奇偶分离,(多项式)状压 DP)
题意
给定一个所有系数都 \(\in \{0,1\}\) 的 \(n-1\) 次多项式 \(P\),求 \(P^{k}\) 中有多少项的系数为奇数。
\(n\leq 20\),\(k\leq 10^{16}\)。
题解
考虑快速幂,有两个方向:
- 计算 \(f^{2^k}\),卷积。
- 通过 \(f^{i}\) 递推到 \(f^{2i}\) 和 \(f^{2i+1}\)。
第一个方向的卷积不保证项数,倒闭。
考虑第二个方向,根据模二性质,有:
考虑 DP,我们无法处理第二个式子后面的 \(f(x)\)。
正常 DP 思路,把不能处理的东西记到状态里,记 \(dp_{i,g}\) 表示 \(k\) 的高 \(i\) 位的 \(f^{?}(x)\) 乘上 \(g(x)\) 的 \(\text{popcnt}\),\(g\) 是一个多项式(额好像记多项式为状态不是很正常,但确实能做)。
推式子。
由于是 \(popcnt\),\(f(x^2)\) 与 \(f(x)\) 等价,考虑将 \(g\) 奇偶分离,将式子写成 \(f(x^2)\) 的形式。
奇偶项相加互不干扰,即 \(dp_{i,g}\leftarrow dp_{i-1,F}+dp_{i-1,G}\),其中 \(F,G\) 是 \(g\) 奇偶分离后的两个多项式。
\(f^{2i+1}\) 同理,每次奇偶拆分会将项数除以二,因此 \(g\) 的项数不超过 \(n\),状压存 \(g\) 即可。
需要预处理所有 \(g\) 所拆成的 \(F\) 和 \(G\)。
提交记录(qoj原题)。
NOIP 模拟 T4(树剖处理树上邻域)
题意
给定一棵 \(n\) 个节点的无根树,边有边权,定义两点的距离为两点之间路径上的边权和。
初始树上有若干关键点,每个关键点 \(p_i\) 有安全系数 \(k_i\) 代表其 \(k_{i}\) 邻域内的点为安全点。即对于 \(\forall dis(u,p_i)\le k_i\),\(u\) 为安全点。
令 \(m\) 为当前最大关键点编号,给出 \(q\) 次操作,每次操作根据 \(opt\) 分为三种:
- \(opt=1\),令 \(m\) 为 \(m+1\),加入一个新的关键点在点 \(p_m\) 处,其安全系数为 \(k_m\)。
- \(opt=2\),删除编号为 \(x_i\) 的关键点,数据保证关键点 \(x_i\) 存在。
- \(opt=3\),询问 \(u_i,v_i\) 两点间路径是否都是安全点。
\(n\leq 500000\),4s,512MB。
题解
可能有点分树做法但我不会。
暴力:将每个关键点赋值 \(-k_i\),跑 dij,安全点即 \(dis\leq 0\) 的点。
考虑维护每个点的 \(a=-dis\) 值,表示第 \(i\) 个点还能往外扩 \(a_i\) 个单位长度。
考虑树剖,修改时暴力在每个链上做性质 A。查询单 \(\log\),修改复杂度爆炸。
当然我们不需要 \(a\) 的全部信息,我们只需要修改垂直于这个重链的位置的 \(a\),然后在查询时查 \(\max_{i\in \text{chain}} \{a_i-|dep_i-dep_u|\}\)。
换一种思路,修改在当前重链上做性质 A,查询枚举重链,查询复杂度爆炸。
考虑平衡,设修改点为 \(u\),查询点为 \(v\),对于 \(u\) 扩展到 \(v\) 的过程,有 \(\text{path}(u,v)=\text{path}(u,\text{lca}(u,v))+\text{path}(\text{lca}(u,v),v)\)。
考虑一半查询管一半修改管,具体地,每次对 \(u\) 到根连的重链做性质 B,在垂直点 \(x\) 打上 \(k-(dep_x-dep_u)\) 的标记,查询时查 \(v\) 的到根连上的重链。
每个重链开一个线段树,拆绝对值维护 \(\max_{i\in \text{chain}} \{a_i-|dep_i-dep_u|\}\) 即可。
具体地每个点维护一个 set 表示当前这个点的 \(a\) 的标记,更新标记时从 set 中查最大值更新线段树。
查询路径时对每个重链找到这条链最下面一个【没有被经过当前重链上的修改覆盖的点】进行检验即可,因为此时没有被覆盖的点只能被上面的点覆盖,所以选最下面一个点是最紧的。
所以还要开一颗线段树维护操作到根连对途径重链的覆盖情况。
三 \(\log\),但是能过。
NOIP 模拟 T2(最短路)
题意
isj2OO9 是著名的网络探险家,负责在复杂的数字城市网络中导航。这个网络由 \(n\) 个节点和 \(m\) 条有向边组成。每条边 \(i\) 都有特定的通行成本 \(w_i\),且 \(w_i\) 为非负值。
最近,网络中出现了一些新的安全协议:对于第 \(i\) 条边,存在 \(k_i\) 条边 \(t_{i,1\sim k_i}\),不能在经过这些边后立刻走第 \(i\) 条边。
isj2OO9 的任务是从起点节点 \(1\) 出发,找到到达所有其他节点的最短路径,同时遵守这些限制。如果某个节点无法到达,isj2OO9 将标记为 -1,表示该节点不可访问。
现在,请你帮助 isj2OO9 解决这个问题:给定图 \(G\) 和限制条件,计算从节点 \(1\) 到所有点的最短路径。
题解
我是奶龙。
点权最短路中每个点只会被松弛一次,特殊图上复杂度可以和实际边数无关。
因此把边看成点暴力松弛即可,即使边数高达 \(m^2\),松弛时间复杂度也是对的。
NOIP 模拟 T3/P11802 【MX-X9-T6】『GROI-R3』Graph(分析性质,计数 DP,分步转移)
题意
特工 isj2OO9 奉命潜入一个秘密组织的内部通信网络。
该网络由 \(n\) 个节点(编号为 \(1 \sim n\))组成,每个节点代表一个通信终端。
由于组织的安全协议,每个终端的入度和出度均不超过 \(1\),这意味着网络由若干条链和环构成,甚至可能存在孤立节点(即入度和出度均为 \(0\) 的终端)。
isj2OO9 的任务是重构该网络,通过增加若干条边,使得网络满足以下条件:
- 每个节点的入度和出度恰好为 \(1\)(即网络由若干不相交的环组成)。
- 如果两个非孤立节点在重构后的网络中位于同一连通块(定义为准无向连通块,即忽略边方向后的连通分量),那么它们在原网络中也必须位于同一连通块。
- 存在一张有向图 \(G\),满足其每个点出度恰好为 \(1\),且使得重构后的网络上存在边 \((u,v)\) 当且仅当在 \(G\) 上从 \(u\) 走恰好 \(k\) 步后可以到达 \(v\)。
isj2OO9 需要计算所有可能的加边方案数,以便评估任务的成功概率。由于结果可能很大,请输出答案对 \(998244353\) 取模的值。
要求小常数 \(O(n^3)\)。
题解
模拟赛赛时认为 \(\gcd\) 必须等于 \(1\),爆零了/ll。
看来考试时要把发现结论的依据写一写(周期结论)。
首先由题意,\(G\) 上任意一个点能走到他自己,因此 \(G\) 是若干环的并。
得到 \(\gcd=1\) 的错误结论是由于周期结论的直觉,让我们仔细想想这个结论能带给我们什么信息。
对于 \(G\) 上一个长为 \(len\) 的环,我们从一个点出发,每次走 \(k\) 步,能得到 \(\gcd(k,len)\) 个长为 \(\frac{len}{\gcd(k,len)}\) 的环。
因此,我们还可以选择把若干个相同长度的环在 \(G\) 中拼在一起。
具体地,用若干个长度为 \(i\) 的环拼成长为 \(i\times t\) 的大环,则有:
因此,设 \(cntloop_i\) 表示环长为 \(i\) 的环数,找到最小的 \(t\) 使得 \(\gcd(\frac{k}{t},i)=1\),则 \(t|cntloop_i\)。这个条件是充要的。
考虑计数 DP。
按链 id DP要记录每个环长的 \(cnt\),不可接受。
因此考虑按需要记录的值 DP,这样的好处是我们可以在进行 \(i\to i+1\) 的转移时顺便判断 \(i\) 是否合法。
令 \(f_{i,j,k}\) 表示当前处理长度 \(i\),长度为 \(i\) 的链有 \(j\) 个,有 \(k\) 个剩余孤点(记录长度 \(\leq j\) 的链个数不容易保证不重不漏,因此选择 \(=\) 的定义)。
有一个技巧:我们可以把没有闭合的链各加上一个孤点,以保证 \(i\) 增加时链长 \(=i\) 的定义。
然而 \(w\) 个孤点在环上的贡献为 \(w!\),这要求了我们不能实时计算这个贡献,只能在最后计算。
具体地,我们在转移时不区分孤点,最后乘上孤点个数的阶乘,根据组合意义,这个方法在不存在全是孤点组成的环时正确。
在孤点成环时,我们发现是阶乘和圆排列的区别。
具体地,对于一个 \(x\),设长为 \(x\) 的全孤点环为 \(y\) 个,则我们多算了 \(x^y y!\) 倍,因为我们要:
- 除掉圆排列的循环。
- 当孤点都相同时,这些环没有顺序之分,除掉【最后乘上孤点个数的阶乘】对这些环顺序的错误贡献。
我们尝试用分步的思想来推导 DP 转移方程。
-
加入原图上的长为 \(i\) 的链,这一步是模拟题意。\(f_{i,j,k}\to f'_{i,j+cntlink_i,k}\)(\(cntlink_i\) 指原图上长为 \(i\) 的链个数)。
-
求出最小的 \(t\) 使得 \(\gcd(\frac{k}{t},i)=1\),加入一些环,满足长为 \(i\) 的总环数是 \(t\) 的倍数,形成环有如下两种方式:
- 选出若干孤点构成环。
- 将已有的链闭合形成环。
即枚举 \(c,l\),\(\frac{f'_{i,j,k}\binom{j}{l}}{i^c c!}\to f''_{i,j-l,k-ic}\),转移条件是 \((cntloop_i+l+c)\bmod t=0\)。
-
把没有闭合的链加上一个孤点,\(f''_{i,j,k}\to f_{i+1,j,k-j}\)。
记孤点个数为 \(cnt1\),答案即为 \(f_{n+1,0,0}\times cnt1!\)。
分析复杂度,有 \(ij\leq n,ic\leq k\leq n,l\leq j\)。
\(ij,ic,il\) 各贡献 \(\sum \frac{n}{i}\),\(k\) 贡献 \(n\)。
总复杂度 \(O(n\sum\frac{n^3}{i^3})=O(n^4\sum\frac{1}{i^3})=O(n^4)\)。
在推导时,我们发现没有转移条件时完全可以把【选出若干孤点构成环】和【将已有的链闭合形成环】分步转移做到 \(O(n^3)\)。
把条件改成 \(-cntloop_i-l=c\pmod t\) 仍然可以分步转移,枚举 \(cntloop_i+l\bmod t\) 的值做若干遍即可。
\(O(n^3)\) 卡卡就过 \(n=1000\) 了(逃。
模拟赛 T4 差点没会 \(O(nq)\) 呜呜呜。
这启示我们最优化问题可以将若干上界取 \(\min\),并证明至少取到一个上界。
P8179 「EZEC-11」Tyres 紫(悬浮点函数贪心,DP,类根号分治)
题意
有 \(n\) 套轮胎,滴叉需要用这些轮胎跑 \(m\) 圈。
使用第 \(i\) 套轮胎跑的第 \(j\) 圈(对每套轮胎单独计数)需要 \(a_i+b_i(j-1)^2\) 秒。在本题中,你不需要担心爆胎,安全车,红旗或者不同的比赛策略。
滴叉需要进入维修站来更换轮胎,所消耗的时间为 \(t\) 秒。特别地,滴叉使用的第一套轮胎不需要进站更换。
你需要最小化总时间,总时间等于每圈的时间之和加上进站所花费的时间。
\(1\leq n,b_i\leq 500\),\(0\leq t\leq 500\),\(1\leq m\leq 2 \times 10^5\),\(1\leq a_i\leq 10^9\)。
题解
首先一个轮胎不会被更换又被换回来。
首先 \(t=0\) 可以用堆贪心,因为函数是凹的。
其次我会 DP,\(dp_{i,j}\) 表示前 \(i\) 个轮胎,跑了 \(j\) 圈,决策单调性优化后可以做到 \(O(n^2m\log m)\) 无法通过。
但是我不会这道题。
考虑贪心的本质,对若干凹函数做多重背包的最优化可以贪心。
对于每个下凸函数 \(f_i\),令 \(f_{i,0}\leftarrow f_{i,0}+t\),这样只会破坏前 \(\lceil \sqrt{t} \rceil\) 项的凸性。
因此对于前 \(\sqrt{t}\) 项 DP,然后默认前 \(\sqrt{t}\) 项 全选,后面直接贪心。
这样正确的原因是对于一个实际没有选择的函数 \(f\),选 \(\sqrt{t}\) 到 \(x+\sqrt{t}\) 项不优于选 \(1\) 到 \(x+1\) 项,因为第 \(\sqrt{t}\) 项的函数值已经 \(>f(1)\)。
另一种说法是一个轮胎如果不选择 \(\sqrt{t}\) 前面则一定不会选择 \(\sqrt{t}\) 项后面。
也可以理解成分组背包。
大概思路就是拼接然后证明不连续一定不优,这种方法适用于有悬浮点的函数最优化。
提交记录
P10681 [COTS 2024] 奇偶矩阵 Tablica 紫(行列二分图,容斥)
题意
考虑只包含 \(0\) 和 \(1\) 的 \(N\times M\) 矩阵 \(A\)。
我们称满足以下条件的矩阵是好的:
- \(\forall 1\le i\le N\),\(\displaystyle \sum_{j=1}^M A_{i,j}\in \{1,2\}\);
- \(\forall 1\le j\le M\),\(\displaystyle \sum_{i=1}^N A_{i,j}\in \{1,2\}\)。
求出 \(N\) 行 \(M\) 列的好的矩阵的数量,对 \((10^9+7)\) 取模。
\(1\le N,M\le 3\, 000\)。
题解
把 \(01\) 矩阵视为行列二分图,相当于要求每个点度数为 \(1\) 或 \(2\)。
枚举左侧二度点个数 \(x\),相当于把 \(n+x\) 个球放入 \(m\) 个盒子,球有些相同有些不同,盒子都不同,盒子中有 \(1\sim 2\) 个球。
先假设所有球都相同令 \(g_{i,j}\) 表示 \(i\) 个球 \(j\) 个盒子的方案数,转移仿照斯特林数。
由于一个点连出的两条边相同,因此以 \(\frac{g_{n+x,m}}{2^{x}}\) 作为答案。
由于可能有重边(在度数为 \(2\) 的点同时指向一个点时发生),因此枚举(钦定)重边个数 \(i\),容斥一下。
一开始我的做法是枚举重边个数然后合并重边为一条边作为子问题,但是这是错的,因为重边调用子问题后仍然会有重边的重边。
这启示我们容斥的时候被钦定的东西不能继续违反条件,即钦定要完全确定一个东西的状态。
其次被钦定的东西是为了去重,因此计算贡献时必须与正常情况无异,即钦定的重边也要除以二(即使算出来不是整数)。
钦定 \(i\) 条重边,系数为 \((-1)^i\binom{n}{i}\binom{m}{i}i!\frac{1}{2^i}\),枚举剩余 \(j\) 个不做要求的二度点。
本质上就是把钦定的点按正确贡献算完后容斥掉,而不是钦定后看成一个新问题或子问题。
\(O(n^2)\)。
提交记录
CF2068D Morse Code *3100(DP 贡献计算技巧,分步转移)
题意
在莫尔斯电码中,字母表中的每个字符被分配一个由点(.)和划(-)组成的序列,且没有序列是另一个序列的前缀。传输字符串时,各字符对应的序列按顺序发送。划的传输时间是点的两倍。
你的字母表包含 \(n\) 个字符,其中第 \(i\) 个字符在你的语言中出现频率为 \(f_i\)。你的任务是设计一个莫尔斯电码编码方案,为每个字符分配点划序列,以最小化单个字符的期望传输时间。即你需要最小化 \(f_1t_1 + f_2t_2 + \cdots + f_nt_n\),其中 \(t_i\) 是传输第 \(i\) 个字符序列所需的时间。
\(n\leq 200\)。
题解
感觉还是对 DP 过程中算贡献和分布转移的理解不是很深刻。
对二叉树形态 DP,由于节点放置不连续,显然要按深度 DP。
\(f_{i,j,k,l}\) 表示 \(i\) 个叶子,\(j\) 个最大深度的叶子,\(k\) 个次大深度的叶子,最大深度是 \(l\),可以做到 \(O(n^5)\)。
我尝试了在转移时算贡献,但是没有成功,因为最终排名不确定。
事实上,DP 过程中算贡献和分布转移本质上是让每个点实时有贡献,并且固定一些点停止贡献。
对于扩展深度为 \(2\) 的点,我们并不用管,因为我们每次只会把点的最浅深度集体下移 \(1\),且点只有在作为最浅深度时才会被固定。
因此这个点的实际深度就是这个点(这个点不存在时我们认为这个点的祖先就是这个点)在状态里的时间 \(-1\)。
令 \(f_{i,j,k}\) 表示固定了 \(i\) 个叶子不再扩展,在未固定的叶子中有 \(j\) 个最大深度、\(k\) 个次大深度的叶子。
则要么固定一个次大深度的叶子,要么把次大深度的叶子全部扩展。
\(w\) 表示 \(p\) 的第 \(i+1\sim n\) 大的和,答案为 \(f_{n,0,0}\),构造方案是简单的。
\(O(n^3)\)。
double 要加上 \(0.5\) 再转为 int 啊啊啊。
提交记录
CF1792F1 Graph Coloring (easy version) *2700(补图性质,计数 DP)
题意
给定一个有 $ n $ 个顶点的无向完全图。完全图是指任意两个顶点之间都有一条边相连。你需要将图中的每条边涂成红色或蓝色(每条边只能涂一种颜色)。
你需要对图进行涂色,使得:
- 至少存在一条红色边;
- 至少存在一条蓝色边;
- 对于每一个满足 $ |S| \ge 2 $ 的顶点集合 $ S \(,\) S $ 要么是红连通的,要么是蓝连通的,但不能同时两者都是。
请计算有多少种不同的涂色方案,并将答案对 $ 998244353 $ 取模后输出。
题解
红蓝互为补图,因此红蓝都不连通的情况不存在。
第一反应是对红蓝都连通的情况容斥,但是发现这样根本做不了。
不妨转化为有一个颜色不连通,对恰有一种颜色不连通的情况计数,此时另一种颜色必定连通。
令 \(f_i\) 表示 \(i\) 个点,每个子集满足蓝色不连通的方案数,枚举与 \(1\) 相连极大的蓝色连通块 \(S\),保证跨过 \(S\) 和 \([1,i]/S\) 的集合中不存在红蓝都连通的集合,这个连通块需要满足红色不连通,用“极大”保证不重。
由于是"极大连通块",所以两个集合之间的连边方案是固定的,只能是红色边。
恰好,这样的连边方式满足【跨过 \(S\) 和 \([1,i]/S\) 的集合中不存在红蓝都连通的集合】,因此逻辑以一种很奇怪的方式自洽了。
由于对称性,红色不连通方案数 \(=\) 蓝色不连通方案数。
则 \(f_i=\sum\limits_{j=1}^{n-1}\binom{i-1}{j-1}\times f_{j}\times (2f_{n-j}-[n-j=1])\)。
乘二是因为当集合有边时可以任意交换红蓝。
提交记录
CF1610G AmShZ Wins a Bet *3300(贪心,trie+hash,DP)
题意
给定一个字符串 \(S\),每次可以删去一个 \(()\) 子序列,求能得到的最小字典序字符串。
\(1\leq |S|\leq 3\times 10^5\)
题解
删除字符的字典序最优化只有后缀的局部最优等于整体最优。
首先删除一个左括号时,贪心地,肯定删除最前的右括号。
并且我们可以把删去一个左括号等价为删除这个左括号连续段中最后一个左括号。
那么我们可以把题目中的子序列改为子串。
那么我们删去一个左括号时,一定会删除后面极短的合法括号串。
删一个合法括号串后变为子问题,考虑 DP,令 \(f_i\) 表示 \([1,i]\) 的答案,记 \(lst_i\) 表示第 \(i\) 个字符向前极短的括号串为 \([lst_i,i]\)(若 \(S_i=(\) 则 \(lst_i=-1\))。
在 \(S_i=(\) 时转移是唯一的。
在 \(S_i=)\) 时有:
把所有 \(f\) 放到 trie 上,相当于动态加叶子的 trie,可以求 \(\text{lca}\) 快速比较字典序。
但是,这是错的。
因为我们对前缀进行 DP 时,局部最优不等于整体最优,比如 \((((()))))\),则应该不删任何东西,但是我们会令 \(f_8=\emptyset\),\(f_9=)\)。
本质上是我们删完前缀的后缀时不知道后面拼接的是啥,后面拼的字符可能影响最优性,局部最优不等于整体最优。
考虑对后缀 DP,则:
需要在反 trie 上加叶子,那么在反 trie 上倍增倍增维护哈希即可。
后缀 DP 的好处是删完后缀的前缀时知道后面拼什么,而前面拼什么不影响后缀串的最优性,因此是正确的。
提交记录
CF251E Tree and Table *3000(子问题划分,分类讨论)
题意
小 Petya 非常喜欢树。最近他的妈妈送了他一棵有 \(2n\) 个节点的树。Petya 立刻决定把这棵树放在一个由 2 行 \(n\) 列组成的矩形桌子上,使得满足以下条件:
- 表格的每一个单元格恰好对应树的一个节点,反之每个树节点也恰好对应表格的一个格子。
- 如果两个树节点之间有一条边,那么它们在表格中对应的两个格子必须有公共边。
现在,Petya 想知道有多少种不同的方式可以将他的树放到桌子上。输出对 \(10^{9}+7\) 取模后的结果。
题解
注意到树的度数不超过 \(4\)。
当树是一条链时,分类讨论,一定是从某点开始走到头,拐回来走一段之后开始走折线,简单讨论后发现答案是 \(2(n^2-n+2)\),注意链可以翻转,翻转后算不同的方案。
对于一般情况,先放入一个三度点,设其为树根。
当根存在一个儿子是叶子时,两侧被划分为了两个子问题,否则枚举儿子放在哪边,也是两个子问题。
容易发现我们有两种不同的子问题:
- 矩形左上(或左下)有一个点,要用这个点的子树铺成一个矩形。
- 矩形左上和左下各有一个点,要用这两个点的子树铺成一个矩形。
设第一种为 \(F(u)\),第二种为 \(G(u,v)\)。
先讨论 \(F(x)\)(假设 \(x\) 在左上)。
-
如果 \(x\) 没有儿子,则无解。
-
如果 \(sz_x=2\),答案为 \(1\)。
-
如果 \(x\) 有两个儿子,则枚举两个儿子是怎么放置的,设放在下面的为 \(u\),右边的为 \(v\)。
- 当 \(u\) 的儿子个数为 \(0\),答案加上 \(F(v)\)。
- 否则,\(u\) 的儿子个数必为 \(1\),答案加上 \(G(v,son_u)\)。
-
如果 \(x\) 有一个儿子:
- 若子树 \(x\) 为一条链,答案为 \(\frac{sz_{x}}{2}\)。
- 若 \(son_x\) 放在下面,答案加上 \(F(son_{son_x})\)。
- 否则找到最浅的有两个儿子的点,设其为 \(y\),一直直走直到遇到这个点停止,枚举哪个点向下拐。
- 如果向下拐的点(设其为 \(z=son_{y,0}\))有一个儿子,判断一下它能不能把第二行的前缀填满,如果可以,答案加上 \(F(son_{y,1})\)。
- 否则,枚举一下哪个儿子(设其为 \(son_{z,0}\))能把第二行的前缀填满,如果可以,答案加上的 \(G(son_{y,1},son_{z,1})\)。
再讨论 \(G(x,y)\)。
- 如果 \(x,y\) 没有儿子,答案为 \(1\)。
- 如果 \(x,y\) 各有一个儿子,答案为 \(G(son_x,son_y)\)。
- 否则,设 \(x\) 有一个儿子,答案为 \(F(son_x)\)。
复杂度看似 \(O(n^2)\),但是提交后直接过了。
因为 \(G(u,v)\) 被调用时,两个点的深度差不超过 \(1\),每次 \(G\) 往后转移只有一个后继,而这颗树每层节点个数是 \(O(1)\) 的(似乎最多 \(6\)),因此 \(G\) 的总状态是 \(O(n)\) 的。
提交记录
P6898 [ICPC 2014 WF] Metal Processing Plant(2-SAT,生成树性质)
题意
有一个无向完全图,\(i,j\) 的边权为 \(d(i,j)\ \ (0\leq d(i,j)\leq 10^9)\)。
令 \(D(S)=\max_{i,j\in S} d(i,j)\)。
将图划分为两个子集 \(A\) 和 \(B\),使 \(D(A) + D(B)\) 最小。输出这个最小值。
\(1\leq n\leq 200\)。
题解
枚举 \(D(A)\) 双指针 \(D(B)\),使用 2-SAT 检验即可做到 \(O(n^4)\)。
考虑 \(D(A)\) 对点选法造成的限制,将所有大于 \(D(A)\) 的边加入表示如果加入一条边后形成偶环,则这条边本身不提供任何信息,如果是奇环,则直接不合法。
因此建立最大生成树,只有树边加入时是有用的,枚举树边,二分 \(D(B)\) 即可做到 \(O(n^3\log n)\)。
提交记录
CF618F Double Knapsack *3000(弱化条件)
题意
给定两个多重集 \(A\) 和 \(B\),每个多重集中恰好有 \(n\) 个整数,每个整数都在 \(1\) 到 \(n\) 之间(包含 \(1\) 和 \(n\))。
你需要找到 \(A\) 的一个非空子集和 \(B\) 的一个非空子集,使得这两个子集中元素的和相等。子集内可以包含重复元素。
构造方案或报告无解。
题解
子序列选数的一个套路是重排后弱化为选子段。
但实际上本题不用重排。
样例均未报告无解,想想为什么必定有解。
由于值域和长度相同且为 \(n\),考虑模 \(n+1\),假设 \(\sum a>\sum b\),对 \(b\) 的每个前缀 \(0\leq i\leq n\) 找到 \(a\) 最小的前缀 \(j\) 使得 \(\sum_{x\leq i} a_x>\sum_{y\leq j} b_y\),显然二者之差在 \([0,n]\) 之间,如果是 \(0\) 就做完了,否则根据抽屉原理差必定会撞一次,取上一次撞的位置到当前位置的子段,也做完了。
提交记录
NOIP 模拟 T3(整体思想,整体算贡献,分析性质)
题意
ChiFAN 构建了一棵树形分流器 \(T\),其是一棵有 \(2 \times n - 1\) 个节点,以 \(1\) 为根的二叉树,其恰有 \(n-1\) 个有两个儿子的节点与 \(n\) 个没有儿子的叶子节点。
分流器 \(T\) 的每个非叶子节点 \(u\) 上有一个参数为 \(a_u,t_u\) 的分流装置,记点 \(u\) 的左儿子为 \(son_{u,0}\) 右儿子为 \(son_{u,1}\),当点 \(u\) 收到一个大小为 \(x\) 的物品时,假若 \(x\) 大于等于 \(a_u\) 则会将物品分发到节点 \(son_{u,t_u}\) 上,否则会分发到节点 \(son_{u,(t_u+1) \bmod 2}\) 上。
你可以任意地修改每个节点的 \(t_u\) 以及有代价地修改每个点的 \(a_u\),具体而言如果点 \(u\) 的 \(a_u\) 最终被修改为 \(a'_u\),你需要付出 \((a_u-a'_u)^2\) 的代价。你需要保证 \(a'_u\) 是整数。
记 \(f(u,l,r)\) 表示最小花费多少的修改代价(你可以修改 \(a,t\) 的取值,请注意你可以无代价地决定 \(t\) 的取值),才能使得修改后依次往点 \(u\) 分发大小为 \(l,l+1,\dots,r\) 的物品,最终不会有两个不同的物品被分发到同一个叶子节点上。
初始时所有非叶子节点 \(u\) 的 \(a_u = 0\)。
现在有 \(q\) 次操作,第 \(i\) 次操作给出 \(u_i,y_i,v_i,l_{i,1},r_{i,1},l_{i,2},r_{i,2}\),你需要将 \(a_{u_i} \gets y_i\) 后回答 \(f(v_i,l_{i,1},r_{i,1})-f(v_i,l_{i,2},r_{i,2})\) 的值(保证 \(r_{i,1}-l_{i,1}+1=r_{i,2}-l_{i,2}+1\) 并且等于 \(v_i\) 子树内叶子数量)。
操作之间不互相独立,也就是一个操作产生的修改会影响后面的操作。
\(1\leq n\leq 10^6\)。
题解
直接 DP 后发现是二次函数错位取 \(\min\),不可做。
考虑整体算贡献,将子树内若干 \(a\) 拿出来,不难发现他们的值互不相同,不妨设 \(a_i=l+p_i\),\(p\) 是我们定义的 \(1\sim r-l\) 的排列,答案为 \(\sum (a_i-l-p_i)\),拆出来 \(p\) 和 \(l\) 无关,所以策略和 \(l\) 的值没有关系,拆出来随便维护一下就行了。
注意平方拆出来要乘以二。
NOIP 模拟 T1(实际是 T2 难度)(序列转差分)
题意
有一个 \(n\) 的字符串 \(a\) 和一个参数 \(k\),\(a\) 的每一个位置都印有一个字符 o 或者 x 。你可以任意次数的对字符串 \(a\) 进行如下两种操作之一(也可以不操作):
-
选择一个长度为 \(k\) 的区间 \([l,r]\) 。将字符串中第 \(l\) 个到第 \(r\) 个位置(下标从 \(1\) 开始,下同)的字符取反。即
o变成x,x变成o。 -
选择一个长度为 \(k\) 的区间 \([l,r]\) 。如果字符串中第 \(l\) 个到第 \(r\) 个位置的字符全部是一样的,就可以删除它们,然后剩余字符拼接起来。
字符串 \(a\) 某些位置变成了 ? ,表示这个位置既可以是 o 也可以是 x。
有多少个字符串 \(b\) 可能被 \(a\) 通过上述两种操作表示出来?\(b\) 可以是空串。输出答案对 \(10^9+7\) 取模后的结果。
部分分:没有 ?。
题解
考虑部分分。
维护差分数组 \(b\),对于没有问号的情况,\(b\) 存在一个模 \(k\) 等价类,每个等价类只需保证异或和,在没有删除操作时容易计数。
有删除时,删除一个子段会让所有等价类的异或和都改变,因此删除是本质没有影响的,对 \(m=n+1-pk\) 计数即可,注意 \(b\) 的长度是 \(n+1\),因此不能把 \(b\) 删空。
对于问号,其作用是合并两个等价类,即限制了 \(i\bmod k\) 和 \((i+1)\bmod k\) 的等价类的异或和,那么本质上是等价类合并,使用并查集维护,原先的每个等价类方案数是 \(1\),现在每个等价类的内部方案数为 \(2^{连通块大小-1}\),乘上刚刚算的东西即可。
问题是我们是否能把序列删到长为 \((n+1)\bmod k\),那么我们本质上要求 \(b_1=b_2=\dots=0\),但是不对最后 \(n\bmod k\) 项做要求。
这些等价类中第 \(1\sim (n\bmod k)+1\) 项可以任意取,其余项不能任取,维护 \(rsz\) 表示等价类代表元中去掉编号为 \(0\) 和 \((n\bmod k)+2\sim k-1\) 的大小,这部分对答案的贡献为 \(+\prod 2^{rsz-1}\),注意当等价类连通块异或和不为 \(0\) 且 \(rsz=0\) 时这部分无解。
AT_agc020_f [AGC020F] Arcs on a Circle 黑(状压 DP,实数处理技巧,DP 转移处理)
题意
有一个长度为 \(C\) 的圆周,在这个圆周上放置 \(N\) 条圆弧。第 \(i\) 条圆弧的长度为 \(L_i\)。
每条圆弧 \(i\) 都被独立地、以均匀概率,随机地放在圆周上的某个位置。也就是说,从圆周上的一个随机点出发,以该点为起点,出现一个长度为 \(L_i\) 的圆弧。
这些圆弧的放置是相互独立的。例如,圆弧之间可以有重叠、交叉,甚至可以包含其他圆弧。
问:圆周上的所有点都至少被一条圆弧覆盖的概率是多少?圆弧的两端也算作被覆盖。
\(L_i\leq C\leq 50\),\(N\leq \color{red}{6}\)。
题解
小数处理技巧:暴力枚举 \(N\) 个数小数部分的排名。
枚举完把小数部分离散化一下变为 \(NC\) 个点,状压 DP 即可。
注意要先让最长的线段放置,要不然可能存在线段绕环大半圈后回来的情况,此时 DP 有后效性。
DP 时按照线段的左端点为顺序转移,避免计重。
提交记录
P9523 [JOIST 2022] 复制粘贴 3 / Copy and Paste 3 紫(区间 DP,简化转移,操作后置,调和级数)
题意
你可以执行如下几种操作来输入某个字符串,设 \(X\) 为屏幕上的字符串,\(Y\) 为剪切板中的字符串,初始均为空串:
- 操作 A:输入字符 \(c\),即将 \(X\) 更新为 \(X+c\)。
- 操作 B:选择所有字符并剪切,即将 \(Y\) 更新为 \(X\),并将 \(X\) 置为空串。
- 操作 C:将剪切板中的字符串粘贴到当前字符串末尾,即将 \(X\) 更新为 \(X+Y\)。
使用一次操作 A,B,C 分别要花费 \(A,B,C\) 单位时间。
计算出输入一个长度为 \(N\) 的字符串 \(S\) 最少需要花费多少时间。
\(1\leq N\leq 2500\)。
题解
这个操作看起来就很符合区间 DP 的形式。
令 \(dp_{l,r}\) 表示 \([l,r]\) 的生成代价,一个区间形如 \(??? [Y] ??? [Y] ?? [Y] ???\),即若干个字符加上若干个剪切板字符串。
转移时枚举第一个 \([Y]\) 的位置可以做到 \(O(n^4)\),考虑简化转移,要求转移到的区间末尾是 \([Y]\),再用区间扩展转移实现往后加 \(?\),可以做到 \(O(n^3)\)。
我们的贡献和字符串 \(Y\) 在 \([l,r]\) 的出现次数有关,考虑反过来刷表,枚举出现次数以做到调和级数的复杂度。
我们发现我们还要处理 \([x,r]\) 开头 \(?\) 段,可以上数据结构做到双 \(\log\),但是无法通过。
Hint:将操作 A 后置,即允许在字符串开头添加字符。
即 \(dp_{l,r}\to dp_{l-1,r}\),这相当于把操作 A 在操作序列中插入到了头部。
这样我们只需要枚举 \(O(n\ln n)\) 个 \(x\),复杂度 \(O(n^2\ln n)\)。
后置操作 A 本质上就是我们新加入了一个操作 D 是在串前加入字符,然后发现和原问题等价。
实际写的时候写的是 \(dp_{l,r}\to dp_{l,x}\ \ (x>r)\),总之是等价的。
提交记录
P14412 [JOISC 2015] AAQQZ 紫(分类讨论)
题意
给定一个长为 \(n\) 的数组,选择一个区间 \([l,r]\) 进行排序,最大化排序后最长回文子串的长度。
\(1\leq n\leq 3000\)。
题解
首先令答案对原串最长回文子串和众数个数取 \(\max\),这两种情况是平凡的。
之后有两种情况:
- 回文中心在排序区间外。
- 回文中心在排序区间的开头(或结尾)极长相等连续段内(例如 \(443322\color{red}1\color{blue}1\color{red}1223344\))
对于第一种情况,设排序区间在右,枚举回文中心,向两侧扩展后枚举排序区间,当然你可以平衡树维护哈希,但是有简单做法:对左侧最长不升子序列开桶,由于排序后区间是上升的,所以可以维护值域指针 \(ptr\) 表示匹配到了哪个值,最后判断能否向外扩展即可。
对于第二种情况,枚举回文中心不好做,考虑枚举排序区间起点 \(l\),对以 \(l-1\) 结尾的最长不升子序列开桶,此时往后枚举 \(r\),当遇到 \(<a_{l-1}\) 的数时开始记贡献,匹配方式与第一种情况相同,唯一区别是不匹配最小值。
\(O(n^2)\)。
提交记录
P14424 [JOISC 2014] 邮戳收集 / Collecting Stamps 紫(贡献后置,状态简化)
题意
有 \(n + 2\) 个车站从西到东顺次标号为 \(0, \ldots, n + 1\)。有两班电车经过所有车站,方向分别为从西向东和从东向西。乘坐两种电车移动 1 站的耗时都是 \(T\) 秒。
车站 \(1, \ldots, n\) 在两列电车间的月台上设有邮戳台,每个车站的电车到邮戳台之间只能步行,步行消耗的时间分别为 \(U_i, V_i, D_i, E_i\),如图:

你一开始在东向电车上,位于 \(0\) 号车站,你想要在所有邮戳台各盖至少一次邮戳,最终到达 \(n + 1\) 号车站。\(0\) 号车站和 \(n + 1\) 号车站分别只能在开始和结束时经过一次,其它车站可以经过任意多次,每个邮戳台也可以经过任意多次。问你需要花费的最短时间。
\(1\leq N\leq 3000\),\(85\%\) 数据满足 \(N\leq 100\)。
题解
经过一个邮戳台有四种方式:
- \(u+e\)。
- \(d+v\)。
- \(u+v\)。
- \(e+d\)。
考虑在东向电车行走的路线,可以跳过若干邮戳台不走,其余走 \(u+v\),或者走 \(u+e\) 上去,把没走的邮戳台挑若干个走 \(e+d\),挑一个走 \(d+v\) 下去。
注意 \(u+e\) 和 \(d+v\) 可能被走多次。
将 \(e+d\) 和 \(d+v\) 的贡献后置,在转移时加上额外贡献,令 \(f_{i,j,k}\) 表示到了站台 \(i\),有 \(j\) 个邮戳台被指定走 \(d+e\),\(k\) 个邮戳台被指定走 \(d+v\),转移时加上 \(2T(j+k)\) 的贡献,枚举当前有 \(k_1\) 个 \(u+e\) 和前面匹配,\(k_2\) 个 \(d+v\) 和后面匹配。可以做到 \(O(\text{poly}(n))\)。
简化状态,由于在上面只能往左走,因此只有存在没有匹配的 \(d+v\) 时才能匹配存在未匹配的 \(d+e\),另一方面,我们做 \(u+e\) 和 \(d+v\) 的匹配时实际上顺便把 \(d+e\) 走了,可以把向上和向下理解称括号匹配,当存在未匹配的左括号时可以选择 \(d+e\)。
令 \(dp_{i,j}\) 表示到了站台 \(i\),有 \(j\) 个未匹配的 \(d+v\) 的最小代价。
转移时,可以选择 \(u+v\),当 \(j>0\) 时可以选择 \(d+e\)。枚举这个站台有 \(k1\) 个 \(u+e\) 和前面匹配,\(k2\) 个 \(d+v\) 和后面匹配,转移到 \(dp_{i+1,j-k1}\) 或 \(dp_{i+1,j+k2}\)。
前缀和优化可以做到 \(O(n^2)\)。
提交记录
P10433 [JOIST 2024] 棋盘游戏 / Board Game 黑(函数(计算几何),凸包,阈值分治)
题意
给定一个 \(N\) 点 \(M\) 边的无向连通图,无自环。点分为白点和黑点。图上有 \(K\) 个人,每个人初始在点 \(V_i\) 上。
设一个人当前在点 \(x\),他的一次行动将执行如下操作:
- 选择 \(x\) 的一个邻点 \(v\)(必须选),走到 \(v\),并花费 1 的代价。
- 若 \(v\) 是白点,继续重复 1. 步骤。否则结束这次行动。
现在 \(K\) 个人按标号 \(1, 2, \cdots, K\) 依次进行一次行动,第 \(K\) 个人行动完成再轮到第 1 个人行动。对于所有 \(T = 1, 2, \cdots, N\),询问使标号为 1 的人到达 \(T\)(中途经过也可以),所有人的总花费最少是多少。
\(2 \leq N, M, K \leq 5 \times 10^4\)。
部分分 \(K\leq 100\)。
题解
首先 \(1\) 和 \(2\sim K\) 的行动是分开的,先考虑 \(2\sim K\)。
记 \(S(v,i)\) 表示 \(v\) 走 \(i\) 轮的最小代价,\(2\sim K\) 有两种行动方式:
- 在黑点跳出在跳回,代价为 \(2\)。
- 在相邻黑点反复跳,代价为 \(1\)。
第一种短期内更优,第二种长期内更优。
为了到达相邻黑点,必须先经过若干不相邻的黑点,这些黑点之间的距离都不小于 \(2\)。
把两种方式画成关于轮数的函数,第一种是一条直线,第二种是前面一堆斜率超过 \(2\) 的直线,后面拼上斜率为 \(1\) 的直线。
即使有多种方式到达相邻黑点,每种方式的轮数和代价各不相同,但最后只有一个方式会被采用,即截距最小的方案。
求截距最小即求路径长度减去黑点个数最小,\(01\) bfs 即可。
我们把 \(S_v(i)\) 求和得到一轮 \(2\sim K\) 的总代价 \(S(i)\)。
现在考虑 \(1\) 的行动方案,每个行动方案都有轮数 \(c\) 和代价 \(dis\),则答案 \(ans=\min(dis+S(c-1))\),减一是因为 \(1\) 到达这个点后立刻停止。
由于轮数每增加 \(1\) 代价增加至少 \(K-1\),部分分的 \(K\leq 10\) 提示 \(K\) 小时有简单做法,因此考虑根号(阈值)分治。
当 \(K>B\) 时,最优轮数最多比最小轮数大 \(\frac{N}{K}\),分层图 bfs 一下即可求出每个轮数的 \(dis\),这部分复杂度 \(O(\frac{N^2}{K})\)。
当 \(K\leq B\) 时,\(S(i)\) 函数最多 \(K\) 段,每次变化都代表一个人的 \(S\) 斜率由 \(2\) 变为 \(1\),枚举在哪一段,把这一段视作一条直线,这样每个黑点贡献相同,dij 即可,复杂度 \(O(KN\log N)\)。
令 \(\frac{N^2}{B}=BN\log N\),即 \(B=\sqrt{\frac{N}{\log N}}\) 时,复杂度取到 \(O(N\sqrt{N\log N})\)。
其实最难的是发现两种方案有一个临界,这启示我们可以尝试把贡献形式刻画成函数,以发现较好的性质。
P14382 [JOISC 2017] 开荒者 / Cultivation 黑(单调队列,双指针,简化枚举)
题意
给定一个 \(R \times C\) 的 01 矩阵,设为 \(F\)。其只有 \(n\) 个格子为 1,其它均为 0。你可以执行若干次操作,一次操作形如:
- 选取四个方向(\(U/D/L/R\))中的一个,设 \(G\) 为 \(F\) 的每个格子向此方向平移一格形成的矩阵;
- 更新 \(F' \leftarrow F \lor G\),其中 \(\lor\) 定义为对每个格子取 \(OR\)。
求使得 \(F\) 全为 1 所需要的最小操作次数。
\(1 \leq n \leq 300\), \(1 \leq R, C \leq 10^9\)。
题解
记移动次数分别为 \(u,d,l,r\)。
枚举每个点的 \(l\) 和 \(r\),计算 \(u,d\) 的下界即可做到 \(O(R^2n^2)\)。
每一个竖线对 \(u,d,u+d\) 各有一个限制。具体地,把所有跨竖线的点按 \(y\) 排序,则要求:
- \(u+d\geq \max(y_{i+1}-y_{i})\);
- \(u\geq \min(y_i)\);
- \(d\geq C-\max(y_i)\)。
考虑只枚举 \(l+r\),通过移动矩形来求 \(u,d\) 的最松限制,具体地,枚举 \(r\) 并令 \(l=0\),之后将矩形向右移动 \(r\) 格,每移动一格更新一次答案。
每移动一格会加入一个竖线,再删除一个竖线,使用单调队列维护竖线,每个竖线暴力计算限制,一共 \(O(n)\) 种竖线,可以做到 \(O(Rn^2)\)。
不难发现,对于一个竖线,扫到的点的 \(x\) 是一个区间,我们预处理每个区间的限制,每次加入竖线时双指针找到区间查表,即可做到 \(O(n^3+Rn)\)。
考虑简化枚举,由于限制是二元的,考虑对每个二元组统计其限制情况,只枚举以下的 \(r\):
- \(0\)。
- \(r=x_j-x_i\ (x_j\geq x_i)\),即 \(i\) 和 \(j\) 是否存在一个时刻会产生限制。
- \(r=R+x_j-x_i\ (x_j\geq x_i)\),表示 \([x_i,x_i+r]\) 和 \([x_j,x_j+r]\) 的限制中,\([x_i,x_j)\) 和 \([x_i+r,x_j+r)\) 能否同时进入矩形边框。
[CSP-S 2025] replace 紫(Trie,二维数点)
题意
给定 \(n\) 个字符串二元组,第 \(i\) (\(1 \leq i \leq n\)) 个字符串二元组为 \((s_{i,1}, s_{i,2})\),满足 \(|s_{i,1}| = |s_{i,2}|\),其中 \(|s|\) 表示字符串 \(s\) 的长度。
对于字符串 \(s\),定义 \(s\) 的替换如下:
- 对于 \(s\) 的某个子串 \(y\),若存在 \(1 \leq i \leq n\) 满足 \(y = s_{i,1}\),则将 \(y\) 替换为 \(y' = s_{i,2}\)。具体地,设 \(s = x + y + z\),其中 \(x\) 和 \(z\) 可以为空,“+” 表示字符串拼接,则 \(s\) 的替换将得到字符串 \(s' = x + y' + z\)。
小 W 提出了 \(q\) 个问题,第 \(j\) (\(1 \leq j \leq q\)) 个问题会给定两个不同的字符串 \(t_{j,1}, t_{j,2}\),她想知道有多少种字符串 \(t_{j,1}\) 的替换能够得到字符串 \(t_{j,2}\)。两种 \(s\) 的替换不同当且仅当子串 \(y\) 的位置不同或用于替换的二元组 \((s_{i,1}, s_{i,2})\) 不同,即 \(x, z\) 不同或 \(i\) 不同。你需要回答小 W 提出的所有问题。
题解
补坑。
赛时由于被 T1 狙杀导致没时间写了,最后把相同部分替换为 # 后没想到 trie,想了个 ACAM 做法根本不可写。
把相同部分替换为 # 后相当于 \(s\) 串的前面是 \(t\) 的前面的后缀,\(s\) 串的后面是 \(t\) 的后面的前缀,对每个不同的 # 开 trie 后二维数点即可。
提交记录
[CSP-S 2025] employ 紫(贡献后置,匹配型 DP)
题意
小 Z 可以选择一个 \(1 \sim n\) 的排列 \(p\),然后在第 \(i\) (\(1 \leq i \leq n\)) 天通知编号为 \(p_i\) 的人前来面试。
第 \(i\) (\(1 \leq i \leq n\)) 天的面试题的难度为 \(s_i \in \{0,1\}\),其中 \(s_i = 0\) 表示没有人能够做出;\(s_i = 1\) 表示所有人都能做出。如果面试者没有做出面试题,则会拒绝,否则会录用。
编号为 \(i\) (\(1 \leq i \leq n\)) 的人若在他之前已经有不少于 \(c_i\) 人被拒绝或放弃参加面试,则他也将放弃参加面试。
小 Z 想知道一共有多少种面试的顺序 \(p\) 能够让他们录用至少 \(m\) 人。求能够录用至少 \(m\) 人的排列 \(p\) 的数量对 \(998244353\) 取模。
\(1\leq n\leq 500\)。
题解
会了贡献后置但是不会推式子,要练组合数学了。
首先这是一个匹配问题,具体匹配方案如下:
- 当这个点值为 \(1\),且有人被录取时,匹配一个 \(c\) 大于【之前失败人数】的人。
- 当这个点值为 \(1\),且无人被录取时,匹配一个 \(c\) 小于等于【之前失败人数】的人。
- 当这个点值为 \(0\) 时,匹配任意一个人。
匹配问题考虑 DP + 贡献后置,按 \(c\) 的值 DP,令 \(f_{i,j,k}\) 表示 \([1,i]\) 拒绝 \(j\) 个人,匹配了 \(k\) 个 \(c>j\) 的人的方案数。
\(j\) 既代表当前拒绝的人数,也代表 \(c\) 匹配到的值,在本题中可以合并成一维状态。
记 \(cnt_i=\sum\limits_x [c_x=i],pre_i=\sum\limits_{x=1}^{i} cnt_x\)。
\(\sum [s_i=1]\leq 18\) 的部分分启示我们暴力枚举每个点的状态:
- \(s_i=1\),实际有人录取,则有:$$f_{i,j,k}\to f_{i+1,j,k+1}$$
\(\tiny{\text{以上是我自己会的部分 qwq}}\)。
-
\(s_i=1\),实际无人录取,有一个 \(\leq j\) 的 \(c\) 与当前位匹配,有 \(j\to j+1\),那么我们要枚举 \(c=j+1\) 的有多少和前面匹配,则有:$$\sum\limits_{w=1}^{\min(k,cnt_{j+1})} f_{i,j,k}\binom{k}{w}\binom{cnt_{j+1}}{w}w!(pre_j-(i-k))\to f_{i+1,j,k-w}$$
-
\(s_i=1\),有 \(j\to j+1\),那么我们要枚举 \(c=j+1\) 的有多少和前面匹配,并且我们要讨论与这个位置匹配的人的 \(c\) 是否 \(>j+1\)。
- 当 \(c>j+1\) 时:$$\sum\limits_{w=1}^{\min(k,cnt_{j+1})} f_{i,j,k}\binom{k}{w}\binom{cnt_{j+1}}{w}w!\to f_{i+1,j+1,k-w+1}$$
- 当 \(c\leq j+1\) 时:$$\sum\limits_{w=1}^{\min(k,cnt_{j+1})} f_{i,j,k}\binom{k}{w}\binom{cnt_{j+1}}{w}w!(pre_{j+1}-(i-(k-w)))\to f_{i+1,j+1,k-w}$$
讨论到这里,我们发现已经没有必要枚举每个点状态了,直接转移所有可能的情况就做完了。
注意统计答案时必须要求 \(k=n-pre_j\)。
提交记录
P4859 已经没有什么好害怕的了 紫(二项式反演,匹配型 DP)
题意
将 \(a\) 数组与 \(b\) 数组匹配使得 \(a>b\) 恰好比 \(b>a\) 的对数大 \(k\) 对,求方案数。
\(1\leq n\leq 2000\)。
题解
令 \(t=\frac{n-k}{2}\)。
二项式反演,钦定 \(i\) 个 \(a>b\),其余不管的方案数为 \(g_i\),则 \(ans=\sum\limits_{i=t}^{n} \binom{i}{t}(-1)^{i-t}g_i\)。
匹配型 DP 求出 \(g_i\),具体地令 \(f_{i,j}\) 表示 \(b[1\sim i]\) 中有 \(j\) 个匹配了比他小的 \(a\) 的方案数,限制由严到松,因此转移是容易的。
最后 \(g_i=f_{n,i}\times \color{red}(n-i)!\),不要忘了这个系数,表示其余的匹配任意。
提交记录
NOIP 模拟 T2/utpc2022_f(冒泡排序扩展)
题意
给定长为 \(N\) 的排列 \(P\) 和一个参数 \(K\),求:
for (int i = 1; i <= N; i++) {for (int j = 1; j <= N - i - K + 2; j++) {if (is_sorted(P[j], P[j + 1], ..., P[j + K - 1])) {sort(P[j], P[j + 1], ..., P[j + K - 1]) ... (1)}}
}
执行以下伪代码表示的算法时,(1)的公式执行几次?
部分分:\(\forall_{i\leq K},P_i=i\)。
题解
\(k=2\) 是逆序对个数。
冒泡排序的经典转化是记 \(b_i=\sum\limits_{j=1}^{i-1}[a_j<a_i]\),然后分析 \(b\) 的变化。
发现我们在维护排序区间时,区间排序前的前 \(k-1\) 个位置是当前前缀的最大值。
考虑部分分,此时每次挪动排序区间,\([i-k,i-1]\to [i-k+1,i]\) 时,发现只会改变 \(b_i\),且此时 \([i-k+1,i-1]\) 已经有序,因此这次排序会让 \(b_i\) 变为 \(\min(0,b_i-k+1)\),可以直接求得答案为 \(\sum\limits_{i=1}^{n} \lceil \frac{b_i}{k-1}\rceil\)。
否则,可能存在一些点在 \([1,k]\) 一起排好的情况,特判一下,如果 \(i\) 的 \(b\) 值在减到 \(0\) 的前一次,\(i\) 的位置到了 \([1,k]\),那么它可能和其他数共用一次排序,这部分也是好处理的。
注意 \(i\) 在 \(t\) 次操作后(\(t<\lceil \frac{b_i}{k-1}\rceil\))的位置为 \(i-t\times (k-1)\) 而不是和 \(a_i\) 相关的式子,因为此时比 \(a_i\) 小的数不一定排在 \(a_i\) 前面。
提交记录
NOIP 模拟 T3(整除分块,容斥,信息复用)
题意
称函数 \(f: \mathbb Z ^ + \to \mathbb Z\) 为积性函数,当且仅当:
- \(f(1) = 1\)。
- \(\forall \gcd(x, y) = 1, f(xy) = f(x) f(y)\)。
可以证明,如果我们对所有素数 \(p\),正整数 \(k\) 知道了 \(f(p ^ k)\) 的值,就可以唯一确定函数 \(f\)。
给定积性函数 \(g\) 和序列 \(a_1, a_2, \cdots, a_n\),初始时满足 \(\forall x, g(x) = 1\)。
你需要维护这个积性函数,并支持以下两种操作:
- 给定参数 \(p, k, x\),表示将 \(g(p ^ k)\) 的取值修改为 \(x\)。
- 查询 \(\sum _ {xy \le n} g(x) a_y\),由于答案可能很大,你只需输出其对 \(2 ^ {64}\) 取模的结果。
题解
赛时干了一些没有道理的事情,对 \(a\) 整除分块,然后啥也不会。
显然难点在于维护 \(g\) 而不是 \(a\),对 \(g\) 整除分块,记 \(g\) 的前缀和为 \(G\),答案为 \(\sum\limits_{i=1}^{n} a_iG(\lfloor \frac{n}{i}\rfloor)\)。
只需要维护 \(O(\sqrt{n})\) 个 \(G\),考虑每次修改暴力重构。
当我们修改 \(g\) 时,需要把修改视为 \(g\leftarrow g+\Delta\) 而不是 \(g\leftarrow x\),因为后者的修改式子涉及除法。
当我们修改 \(g_{p^k}\) 时,对于一个 \(G(i)\) 的影响是 \(G(i)\leftarrow G(i)+\Delta\sum\limits_{j\bmod p\neq 0,j\leq \lfloor \frac{i}{p^k}\rfloor} g_j\)。
令 \(S_p(i)=\sum\limits_{j\bmod p\neq 0,j\leq i} g(i)\),则 \(G(i)\leftarrow G(i)+\Delta S_p(\lfloor \frac{i}{p^k}\rfloor)\),我们也只需要维护 \(O(\sqrt{n})\) 个 \(S\)。由于每个修改的 \(p\) 固定,以下简记 \(S_p\) 为 \(S\)。
由于 \(\lfloor \frac{i}{p^k}\rfloor=\lfloor \frac{\lfloor \frac{n}{t}\rfloor}{p^k}\rfloor=\lfloor \frac{n}{tp^k}\rfloor\),因此状态数是 \(O(\sqrt {n})\) 的。
对于 \(S\),考虑容斥, \(S(i)=G(i)-\sum\limits_{x} g(p^x)S(\lfloor\frac{i}{p^x}\rfloor)\),复杂度 \(O(Q\sqrt {n}\log n)\)。
这个式子很难优化了。
记整除分块能取到的位置为关键点,考虑复用 \(S\) 的信息,由上一个关键点递推出当前关键点。
记上一个关键点的位置为 \(i'\),则 \(S(i)\leftarrow S(i')+G(i)-G(i')-\sum\limits_{x}(S(\lfloor\frac{i}{p^x}\rfloor)-S(\lfloor\frac{i'}{p^x}\rfloor))g(p^x)\),枚举到 \(\lfloor\frac{i}{p^x}\rfloor=\lfloor\frac{i'}{p^x}\rfloor\) 时停止,这样复杂度不高于 \(O(Q\sqrt {n}\log n)\)。
注意算 \(S\) 时用到的是修改前的 \(G\)。
复杂度 \(O(Q(\sum\limits_{i=2}^{n} \log(\lfloor \frac{n}{i-1} \rfloor-\lfloor \frac{n}{i} \rfloor))\),并定义 \(\log 0=0\)。
有经典结论 \(\sum\limits_{i=2}^{n} \log(\lfloor \frac{n}{i-1} \rfloor-\lfloor \frac{n}{i} \rfloor)=O(\sqrt {n})\),因此复杂度 \(O(Q\sqrt {n})\)。
NOIP 模拟 T4/P9104 [PA 2020] Królewski bal(二分图最大匹配,贪心,调整法)
题意
用矩形若干异或的形式给出一个 \(n\times n\) 的 \(01\) 矩阵,把 \(0\) 看做左部点,\(1\) 看做右部点,如果两个不同值的点在同一行或同一列则连一条边。
有 \(q\) 次修改,每次反转矩阵中一个位置的值,你需要实时维护这个二分图的最大匹配。
\(1\leq n,q\leq 3\times 10^5\)。
题解
最大匹配肯定是不能直接维护的,有两种思路:
- 维护 \(cnt_{0}-\max\{|S|-|N(S)|\}\)。
- 维护 \(n^2-\max |S_{独立集}|\)。
实际上联立一下发现两个式子可以化为 \(\max |S_{独立集}|=cnt_1+\max\{|S|-|N(S)|\}\),这个式子本身可以用调整法说明,即上述两个思路的式子等价,因此我们无需纠结到底用哪个。
考虑维护最大独立集大小,假设我们选择的若干个 \(0\),那么可以选择与这些 \(0\) 不同行且不同列的的 \(1\),并且必定全选。
那么贪心地,我们肯定选择若干行和列,并且将这些行和列的交点上的 \(0\) 全选,不在这些行列交点的 \(1\) 全选。
记我们选择的行编号集合为 \(S\),列编号集合为 \(T\),同时计算 \(S\) 和 \(T\) 是不好做的,考虑使用调整法求最大独立集。
固定 \(T\) 为全集,删掉若干个 \(t\in T\)。
令第 \(i\) 行的 \(0\) 个数为 \(a_i\),第 \(i\) 列的 \(1\) 个数为 \(b_i\),扫描线求得 \(a\) 和 \(b\)。
初始时,最大独立集为 \(\sum\limits_{i\in S} a_i\)。
删掉一个 \(t\),会删除第 \(t\) 列中行编号在 \(S\) 内的 \(0\),加上行编号不在 \(S\) 内的 \(1\)。
独立集大小的变化量为列内的 \(S\) 外的 \(1\) 个数减去 \(S\) 内的 \(0\) 个数,即 \(S\) 外 \(1\) 的个数减去 \(|S|\) 再加上 \(S\) 中 \(1\) 的个数,即 \(b_i-|S|\)。
我们发现调整时每列独立,且变化量只与 \(|S|\) 有关。
贪心地,我们枚举 \(|S|\),选择前 \(|S|\) 大的 \(a\),之后求 \(\sum \max(0,b_i-|S|)\)。
那么我们可以轻松得到 \(O(nq)\) 的做法。
写一下最大独立集大小的式子,先把 \(a\) 从大到小排序。
我们发现这个东西可以用线段树维护,具体地令 \(f(x)=sa_x+\sum\limits_{i=1}^{n} [b_i\geq x]b_i-x\sum\limits_{i=1}^{n} [b_i\geq x]1\),开一颗线段树维护 \(f\),每次会把 \(a\) 的某一位和 \(b\) 的某一位加减 \(1\),每次修改实现 \(a\) 的单点加减,实时维护 \(a\) 有序并维护 \(a\) 的前缀和,\(b\) 的修改也是好维护的。
提交记录
二分边界无解时返回的数要符合定义,返回 \(0,n+1\) 而不是 \(1,n\),写错调了好久(记得 CSP-S 2023 T2 也是这么死的)。
[AGC010F] Tree Game 蓝(博弈论,换根 DP)
题意
有一棵包含 \(N\) 个顶点的树,顶点编号为 \(1\) 到 \(N\)。此外,第 \(i\) 条边连接了顶点 \(a_i\) 和顶点 \(b_i\)。
现在,每个顶点 \(i\) 上放有 \(A_i\) 个石子。高桥君和青木君打算用这棵树进行游戏。
首先,高桥君选择一个顶点,并将棋子放在该顶点上。之后,从高桥君开始,双方轮流进行以下操作:
- 从当前棋子所在的顶点取走一个石子。
- 然后选择一个与当前顶点相邻的顶点,将棋子移动到该顶点。
如果当前棋子所在的顶点没有石子可取,则无法进行操作,该玩家判负。请你求出所有高桥君可以选择并保证获胜的初始顶点编号,并按升序输出。
\(1\leq N\leq \color{red}10^6\)。
标红的原因是原题是 \(3000\),但是可以做到 \(O(N)\)。
题解
肯定要考虑树上 DP,令 \(f_i\) 表示子树 \(i\) 内,\(i\) 开始是否先手必胜,通过换根求答案。
对于叶子节点,先手无法行走,\(f=0\)。
对于树上的一个节点。
- 如果其叶子节点全部是先手必胜态,那么走到叶子后另一方可以控制节点不出子树,因此这个点先手必败。
- 否则,当前先手必定前往一个先手必败的子树,此时另一方必定不进入子树,即另一方会走回来。也就是说,情况退化为菊花。
对于菊花,是简单的,设菊花根为 \(u\),叶子中 \(A\) 的最小值为 \(A_{\min}\),当 \(A_{\min}<A_{u}\) 时先手必胜,否则先手必败。
博弈论限定范围时,只需要考虑先手在最优情况下能否限制后手不走出范围,无需考虑后手尝试走出范围的 case。
提交记录
[AGC025E] Walking on a Tree 黑(构造,欧拉回路)
题意
高桥君计划在树上进行 \(M\) 次散步。第 \(i\) 次散步将按以下方式进行:
- 给定两个顶点 \(u_i\) 和 \(v_i\)。从顶点 \(u_i\) 移动到顶点 \(v_i\),或者从顶点 \(v_i\) 移动到顶点 \(u_i\),且同一条边不会被重复经过。
此外,第 \(i\) 次散步的乐趣定义如下:
- 在第 \(i\) 次散步中经过的边中,满足以下任一条件的边的数量:
- 本次散步中首次经过的边;
- 之前曾经经过但仅以相反方向经过的边。
高桥君希望通过为每次散步选择方向,使得 \(M\) 次散步的总乐趣最大化。计算最大总乐趣,并构造方案。
\(1\leq N\leq \color{red}10^6\)。
标红的原因是原题是 \(2000\),但是可以做到 \(O(N\log N)\)。
题解
事实上欧拉路径可以视作添加一条边的欧拉回路,构造时要求:“每条边只经过一次”或“出入度不超过 \(1\),考虑欧拉回路。
我们希望一条边的两个方向都被经过。如果能实现,则答案取到上界 \(\sum \min(cnt_i,2)\),其中 \(cnt_i\) 表示第 \(i\) 条边被经过的次数。
手玩一下发现本质上是在 \(u_i - v_i\) 的图上走,每条边只经过一次。一个想法是欧拉回路,假如我们规定每条边在两个方向经过的次数相同,则我们可以把图建出来,对每个连通块跑欧拉回路。
当存在欧拉回路时就做完了,否则,\(u-v\) 图存在若干点的度数是奇数,这些点的个数为偶数个。
实际上每条边正反经过的次数相同这个条件过于严格,例如当 \(M=1\) 时一定无法满足。
我们发现限制每条边经过正反次数的绝对值之差 \(\leq 1\) 也能满足条件,仍然考虑欧拉回路,添加一些边使得每个点的度数都是偶数。
只要满足这些添加的边在树上无(边)交集,即不存在两个边覆盖同一条树边,则这个方案就是合法的。
由于度数为奇数的点个数为偶数,自下而上两两配对,可以归纳证明一定有解,且容易构造加边方案。
提交记录
P8326 [COCI 2021/2022 #5] Fliper 紫(欧拉回路,构造,二分图染色)
题意
现有一个包含 \(n\) 块挡板的旧弹球机。
游戏在二维平面内进行,其中每块挡板与坐标轴所夹锐角总为 \(45^\circ\),长度为 \(1\) 个单位。挡板用其中心坐标 \((x_i,y_i)\) 和字符 / 或 \ 来表示。小球在碰到挡板后,其运动方向将会旋转 \(90^\circ\)。注意,挡板的两面都可使小球的运动方向发生偏转。
不难发现,当小球处于弹球机中时,它只有两种结局:
- 沿着某一方向一直运动下去而不碰到挡板
- 处于若干个挡板的循环之中
在翻新弹球机的过程中,有四种颜色的染料可供选择。现要将弹球机中的每个挡板进行染色,使得每一个循环内经过每一种颜色的次数相同且为偶数。
请给出一种符合题意的染色方式,或证明这样的染色方式不存在。如果不存在,输出 -1。

题解
对一个点出边染色/要求出入度相差小于等于 \(1\),可以考虑欧拉回路。
默认环长是八的倍数,只需要求四个颜色都相等。
首先将挡板正反两侧拆成两个点,建图,先考虑两种颜色怎么做,首先不能二分图染色,因为一个挡板两侧点可能位于二分图不同侧。
直接做不好做,我们观察性质发现每个点的度数 \(\leq 2\),所以拆点后原图形成若干环和链。
链是不受限制的,先考虑环。
现在我们有 \(n\) 对点,要求每对点颜色相同,考虑点边互换/对偶思想,将环视作点,如果两个点颜色相同则连一条边,本质上我们要对边染色,使得每个点的出边中黑白色相等,跑一个欧拉回路就行了。
现在我们要考虑的是四色,由于默认环一定是八的倍数,所以每个点黑色出边一定是四的倍数。
因此我们把黑色出边的导出子图拿出来在跑欧拉回路,必定有解,白边导出子图同理。
也就是说环长是八的倍数确定有解,现在我们要考虑链,我们把链首尾相接成一个环然后当作环处理,把所有连向链的边都指向这个环,
注意虚点上要连接一些自环满足虚点的度是八的倍数(其实四的倍数就行,因为只需要求虚点的欧拉回路有解就行)。
提交记录
[AGC067D] Unique Matching 黑(唯一匹配增广路性质,DAG 容斥,子问题划分技巧)
题意
定义 \(n\) 个区间是好的,当且仅当:
- \(1 \leq l_i \leq r_i \leq N\)。
- 存在唯一的 \(N\) 阶排列 \(x_1,x_2,\cdots,x_N\),使得 \(x_i \in \left[ l_i , r_i\right]\)
给定整数 \(N\)、素数 \(P\)。求有多少组 \(\left[l_1,r_1\right],\left[l_2,r_2\right],\cdots,\left[l_N,r_N\right]\) 是好的。答案对 \(P\) 取模。
\(2\leq N\leq 5000\)。
题解
DAG 容斥不只局限于 \(n\leq 15\),\(m\leq \frac{n(n-1)}{2}\)。
将匹配二分图建出,完美匹配唯一的充要条件是增广路无环。可以通过反证法证明。
现在问题是匹配边不固定,由于区间之间没有区别,不妨设第 \(i\) 个区间匹配数字 \(i\),最后答案乘上 \(N!\)。
增广路是未匹配边和匹配边交替的路,匹配边即 \(i\leftarrow [l_i,r_i]\),我们套路的把 \([l_i,r_i]\) 和 \(i\) 缩为一个点,则剩余边即 \(i\to [l_x,r_x]/\{i\}\quad (1\leq x\leq n)\),要求剩余边组成的图无环。
这样不好处理,我们不妨换一下二分图两侧边的方向,\(i\to [l_i,r_i]\),这样将 \([l_i,r_i]\) 视作一个点后,未匹配边形如 \(i\to [l_i,r_i]/\{i\}\)。
有向图无环考虑 DAG 容斥,每次加入一些 \(0\) 度点,要求 \(0\) 度即要求不存在其他区间包含这个点。
令 \(f_i\) 表示考虑 \(i\) 个点的方案数,转移时枚举零度点个数 \(j\),直接从 \(f_{i-j}\) 转移是不好限制的。
我们发现这 \(j\) 个零度点把 \(i\) 个点的序列划分成了若干个不交的段,从这些段转移即可。
具体地:
式子的含义表示分配区间端点并乘上 \(j+1\) 个独立子问题的 \(f\)。
枚举 \(v\) 的过程相当于序列划分 DP,直接预处理 \(g_{i,j}\) 是 \(O(n^3)\) 的,我们按照传统序列划分方法,设 \(g_i\) 表示 \([1,i]\),选若干个 \(v\) 且最后一个 \(v=i\) 的带权和(包括 \(-1\) 容斥系数),即可做到 \(O(n^2)\)。
具体地:
答案为 \(n!f_n\)。
提交记录
P4099 [HEOI2013] SAO(树上 DP)
题意
给定一个 \(n-1\) 条边 \(n\) 个点的弱连通 DAG,求拓扑序个数,\(1\leq n\leq 1000\)。
题解
DP,令 \(f_{i,j}\) 表示子树 \(i\) 内 \(i\) 的排名是 \(j\) 的方案数,转移时类似《NOIP 模拟 T3(树上 DP)》。
提交记录
P7213 [JOISC 2020] 最古の遺跡 3(分析性质,贡献后置,子问题划分)
题意
你发现了一行古代石柱的废墟及一份古代文献。古代文献上的记载如下:
- 刚建造完成的时候,有 \(2\times N\) 个石柱,对于 \(1\le k\le N\) 均有两个石柱高度为 \(k\),同时记第 \(i\) 个石柱的高度为 \(h_i\)。
- 会发生 \(N\) 次地震,每次地震会使一些石柱的高度 \(-1\),其他石柱高度不变。
- 石柱 \(i\) 地震时高度不变,当且仅当 \(h_i\ge 1\) 并且对于 \(j>i\) 都要有 \(h_i\not=h_j\)
- \(N\) 次地震后,恰好只剩下了 \(N\) 个石柱。
现在有仅存的 \(N\) 个石柱的位置 \(A_1,A_2,\ldots,A_N\),他想让你求出,最初 \(2\times N\) 个石柱高度的修建方案数 \(\bmod~10^9+7\) 的值。
\(1\leq N\leq 600\),四秒时限。
题解
令 \(b_i\) 表示第 \(i\) 个石柱最后的高度,根据题意有且仅有 \(b_{A_i}\neq 0\)。
考虑如何从 \(h\) 求 \(b\),首先我们发现最后 \(b\) 会变成一个排列,因为每次都会固定 \(1\sim N\) 恰一个数不动。排列继续进行操作不会受任何影响,所以进行 \(N\) 次操作等价于不断进行操作。
模拟一下发现每个时刻相同高度的石柱最多有两个,且下一步前面的石柱高度会减一。
一个石柱从不变到减少的状态转变,当且仅当:
- 后面某个石柱上一步减少到了这个高度,之后由于相同高度的石柱最多有两个,因此后面的石柱被固定,前面的石柱开始减少。
- 石柱减少到某个位置,后面不存在高度相同的石柱,石柱被固定。
容易发现,高度为 \(i\) 的石柱位置会不断前移,严谨的说:
- 一个后缀中如果出现了高度为 \(i\) 的石柱,则这个后缀在接下来的时间里必定含有高度为 \(i\) 的石柱。
- 反之,一个后缀中没有出现高度为 \(i\) 的石柱,则这个后缀在之前也没有出现过高度为 \(i\) 的石柱。
从后往前考虑,如果 \(i\) 后面的 \(b\) 出现了 \(1\sim h_i\) 的所有整数,那么 \(b_i=0\),否则,记 \(x\) 表示满足以下条件的最大整数:
- \(x\in[1,h_i]\)。
- 不存在 \(b_j=x\land j>i\)。
那么 \(b_i=x\),因为上述条件表示 \(i\) 后面高度为 \(x\) 的石柱从未出现过,那么 \(i\) 必定变为高度为 \(x\) 的石柱。
现在我们知道了 \(N\) 个 \(b\neq 0\) 的位置,我们需要对 \(h\) 计数。
但是我们不知道如何根据 \(b\) 求 \(h\) 的方案数,所以直接对 \(b\) 的排列进行计数的方法是没有前途的。
考虑直接对 \(h\) DP,模拟 \(b\) 的生成方式,具体地令 \(f_{i,j}\) 表示 \([i,n]\) 中,\(b\) 出现了 \(1\sim n\) 的所有整数,所对应 \(h\) 的方案数。
我们要干的事情是对 \(h\) 进行匹配计数,\(1\sim N\) 的每个数可以被匹配两次,我们记 \(cnt0_i\) 表示 \(1\sim i\) 中 \(b=0\) 的位置个数。
核心思想:贡献前置、不同高度之间的独立性。
为了计算可以填数的数量,我们把两个相同的 \(i\) 视作本质不同的数字,最后除以 \(2^n\)。
讨论 \(b_i\):
- 当 \(b_i=0\) 时,\(h_i\leq j\),\(f_{i,j}\leftarrow f_{i+1,j}\times (2j-(j+cnt0_{n}-cnt0_{i}))\),表示匹配一个 \(\leq j\) 的数,\(\leq j\) 的中 \(j\) 个数已经被用掉并且 \(b\neq 0\)、\(cnt0_{n}-cnt0_{i}\) 个数被用掉且 \(b=0\)。由于 \(j\) 在从后往前的模拟中递增,限制由紧到松,因此转移逻辑自洽。
- 当 \(b_i\neq 0\) 时:
- 当 \(b_i>j+1\) 时,考虑延迟贡献这一部分,先不管,\(f_{i,j}\leftarrow f_{i+1,j}\)。
- 当 \(b_i=j+1\) 时,如果 \([j+2,k]\) 在后面都出现过且 \(k+1\) 没有出现过,则 \(f_{i,k}\leftarrow f_{i+1,j}\)。在这里,我们需要处理之前 \(h_i>j+1\) 所带来的贡献。有 \(j+1\leq b_i\leq k\)。
- 枚举 \(k\),计算 \([j+2,k]\) 都出现的方案数,这部分与之前的状态独立,因此可以直接乘起来。
- 记 \(suf_1=(n-i)-(cnt0_n-cnt0_i)\),我们需要在 \(j-suf_1\) 个数中选 \(k-j-1\) 个数,要求这 \(k-j-1\) 个数排成连续段,则有 \(f_{i,k}\leftarrow f_{i+1,j}\binom{suf_1-j}{k-j-1}(2(k-j+1)-(k-j-1))g_{k-j-1}\),其中 \(g_i\) 表示 \(i\) 个数最后形成的 \(b\) 排成连续段的方案数。容易发现在这次转移后所有未确定的石柱高度都 \(>k\),所以这些石柱不会对当前 \(k-j-1\) 个数排成连续段造成任何影响,即 \(g\) 完全独立。
考虑如何求 \(g_i\)。考虑类似区间 DP 的子问题划分结构,枚举最后一个被固定的石柱的高度,\(g_{i}=\sum\limits_{j=1}^{i} g_{j-1}g_{i-j}\binom{i-1}{j-1}(2(i-j+1)-(i-j))\)。
时间复杂度 \(O(N^3)\),常数极小可以通过。
启示:
- 当 DP 遇到无法处理的 case 时(通常是对另一种转移有后效性),不管这个贡献,放到受影响的转移 case 中后置处理。
- 不知道如何拆分子问题时,可以考查个别数,例如如果把第一个/最后一个满足某条件的元素拿走会怎么样。
提交记录
NOIP 模拟 T3
题意
汤圆的世界可以被看作是一棵以 \(1\) 为根的有根树,节点编号 \(1\sim n\),每个点的父亲编号小于自己。
雨一共会下 \(m\) 个时刻,它的扩散规律如下所述:
- 在第 \(1\) 时刻开始时,节点 \(1\) 会被淋湿。
- 在第 \(2\sim m\) 时刻开始时,每个在前一时刻自己或父亲是湿的的节点会被淋湿。
在第 \(i\) 时刻结束前,汤圆会把以 \(a_i\) 为根的子树擦干,此时它们不再是湿的。
由于汤圆的能力不是无限的,他并不能把根节点擦干,并且也不是每个时刻他会擦干一棵子树。
形式化地说,序列 \(a\) 中没有 \(1\),并且可能存在 \(0\)。对于 \(a_i=0\),在 \(i\) 时刻汤圆什么都不会做。
现在汤圆想要知道,对于每个 \(1\sim n\) 的节点,在这 \(m\) 个时刻中它在多少时刻结束时是湿的。
\(1\leq n\leq 1000000\)。
题解
崭新的维护方式。
对于一个点维护一个数组 \(b_i\),\(b_{i,x}\) 表示点 \(i\) 在 \(x\) 时刻是否是湿的。
考虑一个点在 \(t\) 时刻处于湿状态的充要条件,点 \(i\) 在 \(t\) 时刻湿,需要同时满足:
- \(a_{t}\neq i\)
- \(b_{fa_i,t-1}=1\)
- \(b_{fa_i,t}=1\)
因此 \(b\) 从父亲转移进儿子时,会删除每个 \(1\) 连续段头部的 \(1\),也即将每个 \(0\) 连续段扩展 \(1\)。
每个 \(0\) 的贡献是一个关于深度的一次函数。
dfs 维护,具体地维护一个 set 表示当前点 \(b\) 的每个 \(0\) 开始段,只维护由“擦干操作”产生的初始 \(0\),加入时的操作时 set 维护相邻信息的经典套路,一段信息对应到深度线段树上是区间加等差数列,也是好维护的。
撤销时直接暴力撤销即可。
提交记录
[ARC086E] Smuggling Marbles 紫(长链剖分优化 DP)
题意
すぬけ君有一棵有 \(N+1\) 个节点的有根树。这棵树的节点编号为 \(0\) 到 \(N\),其中节点 \(0\) 是根。对于每个 \(i\)(\(1 \leq i \leq N\)),节点 \(i\) 的父节点是 \(p_i\)。
すぬけ君除了这棵树之外,还用空箱子和弹珠来玩游戏。这个游戏的玩法如下:首先在若干个节点上各放一个弹珠,然后按照以下步骤进行:
- 如果节点 \(0\) 上有弹珠,将该弹珠移到箱子里。
- 把所有弹珠从当前节点同时移动到父节点上。
- 对于每个有两个及以上弹珠的节点,将这些弹珠全部移除。
- 如果仍然存在有弹珠的节点,则回到第 1 步,否则游戏结束。
由于每种弹珠的放法有 \(2^{N+1}\) 种,请你计算所有情况下游戏结束时箱子中的弹珠数之和,并对 \(1,000,000,007\) 取模后输出。
\(N\leq 2\times 10^5\)。
题解
学习长链剖分优化 DP。想到了除长剖以外的部分。
为了推导方便,把计数转为概率。
\(f_{u,i}\) 表示 \(u\) 子树内 \(i\) 轮后 \(u\) 有球的概率,则:
初值为 \(f_{u,0}=\frac{1}{2}\),答案为 \(\sum\limits_{i=0}^{n} f_{1,i}\)。
和深度有关的 DP 考虑长剖。
长剖优化可以做到 \(O(n)\)。
CF995F Cowmpany Cowmpensation *2700(容斥,子集反演(二项式反演))
题意
给定一棵树,给树上每个点赋一个 \([1,D]\) 的值,使得父亲的值大于等于儿子的值。输出方案数对 \(10^9+7\) 取模后的结果。
\(1\leq n\leq 3000\)。
题解
一开始想了两个思路,一个是把 \(=\) 合并之后转拓扑序计数,一个是树上背包维护这个点在子树的相对排名,前者状态就是 \(n^3\) 的,后者状态 \(O(n^2)\) 转移 \(O(n)\),且转移系数不弱于组合数,不可优化。
回归原本的思路,我们希望记录树上使用了 \(k\) 个值的方案数,为了避免计重需要维护相对排名,即出现 \([1,k]\) 的每个值的方案数,最后乘上 \(\binom{D}{k}\)。
要求出现每个值,可以考虑容斥(子集反演),对于 \([1,k]\) 的每个子集算出至多使用子集中的数的方案数,之后容斥。
显然方案数只和子集大小有关,因此容斥是容易的,具体地记 \(f_i\) 表示子树 \(i\) 内至多只用 \([1,i]\) 且根节点的值为 \(i\) 的方案数,\(f\) 可以树上 DP 求出,\(g_i\) 表示整棵树恰好使用 \([1,i]\) 的方案数,则有:
也可以理解成钦定 \(j\) 个数不出现然后做二项式反演。
类似的题还有【ZJOI 小星星】。
提交记录