做题计划 10 月

10.2

CF317C Balance

题目描述

\(n\) 个点,\(m\) 条边的无向图,每个点有一个当前水量 \(a_i\) 和目标水量 \(b_i\)。一次操作可以让两个点通过一条直连的边输水,边输水没有上限,但是一个点的水量不超过 \(V\)。总操作次数不超过 \(2n^2\),输出输水方案。

\(1\leq n\leq 300;0\leq m\leq 5\times 10^4;1\leq V\leq 10^9;0\leq a_i,b_i\leq V\)

做法

切了,定义 \(c_i=b_i-a_i\),在图中肯定可以找到一对点,它们 \(c\) 的正负性相反,那么随便选择两个点中的一个点,现在将它的 \(c\) 归零。

假设要将 \(w\) 的水从 \(a\) 运到 \(b\),找到两点间的任意一条路径 \(a=v_1,v_2,\dots,v_m=b\),为了使中间的点水量始终在 \([0,V]\) 内,从后往前输水,每个点空出足够的容积后,再从前往后填满 \(w\)。

具体来说,对于 \(i\in[1,m-1]\) 的每个点 \(v_i\) 都要恰好输出 \(w\) 的水量。记当前第 \(i\) 个点的水量是 \(x_i\),执行两轮输水操作。

  • 第一轮为了 \(v_i\) 有足够的容积容纳 \(w\) 水量。让 \(i\) 从 \(m-1\) 枚举到 \(2\),将 \(max(0,x_i-(V-w))\) 的水从 \(v_i\) 输到 \(v_{i+1}\),也就是 \(x_i\leftarrow \min(x_i,V-w)\)。倒叙操作是为了 \(v_i\) 不被 \(v_{i-1}\) 影响,因为 \(v_{i-1}\) 输给 \(v_i\) 的水量也是算在总共的 \(w\) 个水里的。

  • 第二轮 \(i\) 再从 \(1\) 枚举到 \(m-1\),将 \(v_i\) 剩下的能输出的水量都输给 \(v_{i+1}\)。由于 \(a\) 的水量肯定大于等于 \(w\),而且第二轮每个点输水时都累计接收了 \(w\) 的水量,不用担心 \(v_i\) 不够水。由于第一轮空出了足够的空间,不用担心 \(v_{i+1}\) 不够空间。

\(c\) 变成 \(0\) 就不管了,这样每次选出两个点之后都会少一个点,最多做 \(n-1\) 次上一段所述操作。前后扫一遍最多不超过 \(2n\),总次数不超过 \(2n^2\)。

无解的情况是:存在一个连通块,所有点 \(a\) 之和不等于 \(b\) 之和。其他情况都是有解的。

10.3

CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

题目描述

一棵点有颜色的树,求每个子树中最长的路径,路径满足出现了奇数次的颜色小于等于一种。

\(maxc\leq 22\)

做法

只关心奇偶性,要求路径上出现的颜色的奇偶性,那么在每个点状态压缩到根的路径上所有颜色出现次数的奇偶性。

要对所有点的子树求解,可以想到树上启发式合并。

P17575 [JAG 2026 Summer Camp #3] Self-Destruct Sequence

题目描述

有一个长为 \(n\) 的序列 \(a\)。假设 \(b\) 为当前的序列,每次可以选择一个位置满足 \(i+b_i-1\leq|B|\),将 \([i,i+b_i-1]\) 的数都删掉,剩下的数按原本的顺序组成更新序列 \(b\)。对于序列 \(a\) 的每个前缀,以此为序列 \(b\) 的初始值,分别求将序列 \(b\) 删空所需要的最大、最小操作数。

做法

很容易想到区间 dp,但是时间复杂度是 \(\mathcal O(n^3)\) 不可接受。

观察区间 dp 究竟做了什么,区间 dp 傻傻地按照题意模拟,把所有可能的情况都 dp 了,如果要统计删空序列的方案数,这是必要的。但是题目只需要求最小、最大操作数。考虑优化不必要的状态及转移。

定义被同一个操作删掉的点是同一组点,下标最小的为代表元。考虑什么情况是绝对不合法的,假设 \(p\) 是某个代表元的位置,它及后面的代表元组内的点的位置都大于等于 \(p\),不用管。但是如果 \(p\) 前面的代表元同组点总数小于 \(p-1\),即前 \(p-1\) 个位置,将所有能删的都删了之后还有剩余就说明最后有一些点无法被删除,这就是唯一不合法的情况。发现一组点只有代表元是重要的,除了不合法情况,非代表的点一定能找到一种安排方式使得符合题目操作,比如将代表元从后往前删。

现在不关心非代表元素,只需记录代表元、前缀代表元的点权和与位置的关系。那么可以得到以下 dp。

设 \(f_{i,j}\) 表示序列 \(b\) 初始为序列 \(a\) 大小为 \(i\) 的前缀时,代表元总点权减 \(i\) 等于 \(j\) 时,代表元个数的最小值。\(j\) 不能小于 \(0\)。

\[f_{i,j}=\min(f_{i-1,j+1},f_{i-1,j-a_i+1}+1) \]

转移的意义是:位置 \(i\) 不是代表元时,下标增加了 \(1\),所以 \(j\) 增加 \(1\)。位置 \(i\) 是代表元时,不仅下标增加 \(1\),前缀点权和还增加了 \(a_i\),操作总次数加 \(1\)。

求最大值同理。

10.4

P6846 [CEOI 2019] Amusement Park

P16902 [CCO 2026] Melborp

P14721 [RMI 2025] 橙子 / Oranges

10.5

P14768 [ICPC 2024 Seoul R] Ladder Update

10.6

字符串专题

CF587F Duff is Mad

题目描述

有 \(n\) 个字符串和 \(Q\) 个询问,每个询问查询一段区间内的串在某个串内总共出现了多少次。

做法

根号分治。

建出所有串的 AC 自动机,对于长度小于 \(B\) 的串,直接遍历这个串的每个前缀,加上这个前缀节点 fail 树上到根的路径上,编号在 \([l,r]\) 内的结尾节点个数。如果对每个前缀都暴力跳 fail 时间复杂度是 \(\mathcal O(n^2)\) 的,显然不能这样。考虑每个结尾节点对前缀节点贡献。先把询问的区间 \([l,r]\) 拆成 \([1,r]-[1,l-1]\),按照串编号从小到大加入结尾节点,它的贡献就是 fail 树上的一个子树,可以用 dfn 序转成序列区间,也就是区间加一。然后查询就直接暴力遍历前缀。

区间修改只有 \(n\) 个,但是查询需要计算的有 \(\mathcal O(n\sqrt n)\) 个,为了平衡复杂度,可以用区间修改 \(\mathcal O(\sqrt n)\),单点查询 \(\mathcal O(1)\) 的分块。

对于长度大于 \(B\) 的串,至多有 \(\dfrac{m}{B}\) 个,\(m\) 是总字符数量。可以用单次线性的做法,比如遍历整个 AC 自动机,求出第 \(i\) 个串在这个大串内出现的次数,查询就直接用前缀和。

处理小串和大串的时间复杂度分别是:\(\mathcal O(QB+n\sqrt n),\mathcal O(\dfrac{m}{B}(m+n)+Q)\),\(B\) 取 \(\sqrt n\) 时最优。

可能会有的时间复杂度错误的想法:

由于所有字符串总和 \(\mathcal O(n)\),对每个 \(s_k\) 暴力遍历其所有前缀,然后在 fail 树上,\(s_k\) 的某个前缀节点到根的路径上,用树剖求出编号在 \([l,r]\) 内的字符串的结尾节点个数。

实际上,时间复杂度是 \(\mathcal O(\sum |s_k|\log^2 m)\) 的,最坏情况下这样是 \(\mathcal O(Qm\log^2 m)\) 的,因为可能每个询问的 \(k\) 都是最长的串,这样就会查询 \(\mathcal O(Qm)\) 次点到根路径的信息。

这一题的两个做法一个依赖字符串长度总和,一个依赖字符串个数,两个做法平衡,互补。

妈的空间只有 256 MB,询问离线不能存 \(QB\) 个(每个串的每个位置都存下来),而是应该同一个串只存这个串的编号。

CF587D

10.8

CF2206A Compare Suffixes

P3181 [HAOI2016] 找相同字符

切了。够熟悉 sa 就比较简单。

题目描述

两个字符串 \(S,T\),定义 \(val(S,T)\) 表示在 \(S,T\) 中分别选一个子串,使得这两个子串相同的方案数。

做法

可以用容斥,定义字符串 \(A=S+"|"+T\),答案就是 \(val(A,A)-val(S,S)-val(T,T)\)。

\(val(S,S)\) 怎么求呢?类比求一个字符串中本质不同的子串个数的做法,用所有后缀的所有前缀表示这个字符串的所有子串,按排名从小到大加入后缀,每加入一个后缀,就求出这个后缀和之前加入的后缀相同前缀的个数。

具体来说,

\[val(S,S)=\sum_{i=1}^{|S|}\sum_j[rk_j<rk_i]\operatorname{lcp}(i,j) \]

然后 \(\operatorname{lcp}(i,j)\) 是 \(ht\) 数组 \([1,rk_i]\) 区间的所有后缀最小值的和,可以用单调栈处理。

AT_abc349_g Palindrome Construction

题目描述

定义一个序列 \(a\) 的某个区间 \([l,r]\) 是回文区间当且仅当对于所有 \(i\in[1,r-l+1]\),都有 \(a_{l+i-1}=a_{r-i+1}\)。

现在给出一个序列 \(T\),你需要构造一个满足以下条件且字典序最小的序列 \(a\),无解则输出 No。

对于每个 \(i\) 需要满足两个条件:

  1. \(\forall j\in[1,T_i],a_{i-j}=a_{i+j}\)。
  2. \(i-T_i=1\) 或 \(i+T_i=n\) 或 \(a_{i-T_i-1}\not=a_{i+T_i+1}\)。

即 \([i-T_i,i+T_i]\) 是以 \(i\) 为回文中心的极长回文区间。

做法

一个 \(T_i\) 的限制是:\(\forall j\in[1,T_i],a_{i-j}=a_{i+j}\) 且 \(a_{i-T_i-1}\not= a_{i+T_i+1}\)。

由于是描述一些二元关系,可以想到连边:

  • 对于要求相等的位置,每一对连一条红边;
  • 对于要求不相等的位置,每一对连一条蓝边。

连完所有红边之后,如果存在一条蓝边的两端点联通,则无解。

若有解,由于要求序列 \(a\) 字典序最小,可以按如下方式贪心构造:

每次找到未确定的最小位置,将其所在的红边连通块的答案定为 \(\operatorname{mex}\{ans_i\mid i\text{的答案已经确定并且}i\text{与当前位置有蓝边相连}\}\)。

具体实现就是对每个极大连通块维护一个不能选的数字集合,从小到大枚举 \(i\),如果当前 \(i\) 的答案未确定,就遍历一遍 \(i\) 所在联通块的不可选数字集合求出整个连通块的答案,然后对于每个这个连通块中的点,遍历其相邻蓝边,更新其他连通块的数字集合。

注意连红边的时候不能 \(\mathcal O(\sum a_i)\) 的暴力连边,可以用类似 manacher 的优化方法,记录当前右端点最大的位置,在最大的右端点左边的位置不需要连边,因为这个右端点的回文串在对称的地方已经连过了,现在已经联通了。

时间复杂度 \(\mathcal O(n)\)。

AT_abc134_f [ABC134F] Permutation Oddness

补 dp 专题。

题目描述

求 \(\sum_{i=1}^n |i-p_i|=k\) 的长为 \(n\) 的排列的个数。

做法

一个容易想到的 dp 是 \(f_{i,S}\) 表示当前选的数的集合为 \(S\),选的数的 \(\sum|i-p_i|=i\) 的排列数,很明显是过不了的。

考虑将绝对值拆开,发现只关心 \(i,p_i\) 的大小关系,贡献就是大的减小的,定义 \(f_{i,j,k}\) 表示前 \(i\) 个位置填前 \(i\) 个数,现在有 \(j\) 个位置没有填数,填好数的位置的 \(\sum|i-p_i|=k\) 的排列数。

转移方程如下,注意下标可能有负数,要用偏移量。

if(j)add(f[i][j][k+pyl],f[i-1][j-1][k+i+i+pyl]);
add(f[i][j][k+pyl],1ll*f[i-1][j][k+pyl]*(2*j+1)%mod);
if(j<i)add(f[i][j][k+pyl],1ll*f[i-1][j+1][k-i-i+pyl]*(j+1)%mod*(j+1)%mod);

AT_agc009_e [AGC009E] Eternal Average

题目描述

10.11

CF1404B Tree Tag

10.12

CF1491E Fib-tree

做法

假设当前分治到的子树大小为 \(f_w\),找到当前子树中子树大小等于 \(f_{w-1},f_{w-2}\) 的节点,随便找一个,断掉它和它父亲的边,分成两棵子树继续递归。

这样做的时间复杂度约为 \(\mathcal O(n\log n)\)。因为斐波那契数列指数级增长,小于等于 \(n\) 的大约只有 \(\log n\) 项。

但是为什么在断掉之后分成的树的大小对的边中随便断一条边就是对的呢?假设当前的树是大小为 \(f_w\) 的 Fib-tree,且大小小于 \(f_w\) 的 Fib-tree 都满足前面说的。假设有一条割边 \(e\) 将这棵树切成大小为 \(f_{w-1}\) 的 Fib-tree \(A\) 和大小为 \(f_{w-2}\) 的 Fib_tree \(B\),有另一条边 \(e0\) 将该树分成大小为 \(f_{w-1},f_{w-2}\) 的两部分。

  1. \(e0\) 就是 \(e\),那么选 \(e0\) 割肯定是没问题的。

  2. \(e0\) 不是 \(e\)。此时 \(e0\) 一定在 \(A\) 内,并将 \(A\) 分成大小为 \(f_{w-2},f_{w-3}\) 的 \(C,D\) 两部分,并且大小为 \(f_{w-3}\) 的那部分与 \(e\) 相邻,那么割掉 \(e0\) 之后 \(D\) 和 \(B\) 组成的树,\(e\) 刚好作为割边。那么先割掉 \(e0\) 再割 \(e\) 和先割掉 \(e\) 再割掉 \(e0\) 得到的状态是一样的,然而先后者是对的,则前者也是对的。所以先割 \(e0\) 也是有合法的割法。

CF1225F Tree Factory

做法

编号是无关紧要的,那就先不管编号。具体的流程是这样的,从根节点出发,将当前节点的儿子按子树内最深节点深度升序排序,回溯时做操作。这样做,最深的叶子一定最后才访问到,操作次数就等于总点数减去最深的叶子的深度 \(maxd\)。

具体代码如下
void dfs(int u,int fat){
	sort(h[u].begin(),h[u].end(),[&](int x,int y){return dep[x]<dep[y];});
	st[++tp]=u;int w=tp;ans.push_back(u);
	for(int v:h[u])if(v!=fat){
		while(tp>w)op.push_back(v),tp--;
		dfs(v,u);
	}
	return;
}

考虑证明下界就是 \(n-maxd\)。每次操作会让选择的节点的子树内的点的深度减一。原本链的深度为 \(n\),为了使最大深度变成 \(maxd\),至少需要做 \(n-maxd\) 次操作,而这个贪心刚好取到了下界,所以是对的。

P9481 [NOI2023] 贸易

做法

发现树高很小,直接暴力跑所有子树的最短路即可。

P7897 [Ynoi2006] spxmcq

做法

先列出 dp 式子。

\[f_u=a_u+x+\sum_{v\in son_u}[f_v\geq 0]f_v \]

发现随着 \(x\) 增大,\(f_u\) 单调不降,那么 \(f_v\geq 0\) 条件在一段后缀成立,由于 \(v\) 对 \(u\) 的贡献是一组二元关系,而贡献存在在一段后缀,可以想到将询问按 \(x\) 升序扫描线,每当 \(f_u\geq 0\) 的时候就连边 \(v\to u\) 并计算贡献。

该图在某个时刻是一个森林,一个点的答案就是其子树内 \(a_v\) 之和加上 \(x\) 乘其子树的大小。

那知道了 \(x\),怎么判断 \(f_u\) 是否大于零呢?令 \(u\) 子树内 \(a_v\) 之和为 \(sum\),子树大小为 \(siz\)。条件就是 \(sum+x\cdot siz\geq 0\),转化一下就是 \(x\geq \lceil -\dfrac{sum}{siz}\rceil\),用小根堆以该值为关键字存未向父亲连边的点就行了。一个点 \(u\) 向父亲 \(fa\) 连边会贡献到的是一条路径,端点是 \(fa\) 和 \(fa\) 所在连通块的最高点,这可以用树上差分 \(\mathcal O(n\log n)\) 单点修区间查。

注意初始化差分数组。

P9058 [Ynoi2004] rpmtdq

做法

类似 rldcot

P14008 「florr IO Round 1」序列游戏

10.16

P9257 [PA 2022] Mędrcy

题目描述

有 \(n\) 个人,\(m\) 条咒语,每条咒语恰好有两个人不知道,每个人知道自己知道的咒语有那些人知道,但是他们并不知道所有咒语的总数,所以一开始每个人都以为自己知道的是全部咒语。

这些人在知道自己知道的咒语不是全部咒语之后就会在下一天离开。

第零天的时候,这些人知道了总咒语的数量大于 \(0\),问 \(k\) 天内最早有人离开的是那一天,并输出那些人离开。

\(3\leq n\leq 10^3;1\leq m\leq 3\times 10^3;1\leq k\leq 30\)

做法

红眼睛蓝眼睛问题加强版。

考虑什么人会在第一天离开,就是那些一个咒语也不知道的人。

定义 \(S_i\) 表示第 \(i\) 个人知道的咒语的集合。考虑在第一天无人离开的情况下,什么人会在第二天离开。就是那些以为有人一个咒语也不知道的人。具体的,\(a\) 会在第二天离开,当且仅当 \(\exists b,S_a\cap S_b=\emptyset\),同理 \(b\) 也会同时离开。为什么 \(a\) 会离开呢?因为 \(b\) 在第一天没有离开,那么就说明 \(b\) 知道咒语,而 \(a\) 却不知道,所以存在咒语不被 \(a\) 知道。

同理可以得出前两天无人离开,而第三天离开的是什么人。如果在 \(a\) 的认知里,\(b\) 以为 \(c\) 一个咒语也不知道,那么 \(a\) 认为 \(b\) 一定会在第二天离开。具体的,\(a\) 会在第三天离开,当且仅当 \(\exists b,c,S_a\cap S_b\cap S_c=\emptyset\)。

那么,一个大小为 \(p\) 的人的集合 \(A\) 会在第 \(p\) 天离开当且仅当 \(A\) 满足 \(S_{a_1}\cap S_{a_2}\cap S_{a_3}\cap\dots\cap S_{a_p}=\emptyset\),且不存在

AI写的充要性证明

这个问题是本题最精妙的认识逻辑学(Epistemic Logic / 知识与公共知识博弈)核心。

要严格证明为什么 \(\bigcap_{i=1}^k S_{a_i} = \emptyset\) 是这 \(k\) 个人在第 \(k\) 天离开的必要条件,我们可以使用数学归纳法,严密还原贤者们在每一天的逻辑推理过程。


一、基本定义与认知模型

  1. 集合定义:

    • 设全天下真实存在的所有咒语全集为 \(E\)(\(|E| = m\))。
    • 贤者 \(u\) 所知晓的咒语集合为 \(S_u \subseteq E\)。
    • 贤者 \(u\) 所不知道的咒语集合为其补集 \(U_u = E \setminus S_u\)。
  2. 离开的充要判定:

    • 规则规定:贤者 \(u\) 在某天午夜离开 \(\iff\) 贤者 \(u\) 能够以 100% 的逻辑确定性推导出 \(U_u \ne \emptyset\)(即天下存在自己不知道的咒语)。
    • 贤者的思考方式(反证法):
      每个贤者 \(u\) 每天都在试图证明反面假设 \(H_0\):“我知道所有的咒语(即 \(E = S_u, U_u = \emptyset\))”。
      • 如果 \(H_0\) 与“前几天没人在午夜离开”的客观事实产生逻辑矛盾,则 \(u\) 推翻 \(H_0\),确定 \(U_u \ne \emptyset\),并在当天午夜离开。
      • 如果 \(H_0\) 依然能与当前的客观现象自洽,则 \(u\) 无法确定自己是否有遗漏,当天绝不会离开。

二、数学归纳法证明

1. 基础情况:第 1 天(\(k = 1\))

  • 流浪者广播:“至少有一个贤者知道至少一条咒语”(即 \(E \ne \emptyset\) 成为全员的公共知识)。
  • 贤者 \(u\) 的推导:
    • 若 \(S_u = \emptyset\)(\(u\) 知道 0 条咒语):
      流浪者说有人知道咒语,而自己一条都不知道,说明该咒语必在 \(U_u\) 中,立刻得出 \(U_u \ne \emptyset\)。因此 \(S_u = \emptyset\) 的人在第 1 天离开。
    • 若 \(S_u \ne \emptyset\)(\(u\) 至少知道 1 条咒语):
      \(u\) 假设 \(E = S_u\)。在此假设下,流浪者说的话(\(E \ne \emptyset\))完全成立,没有任何逻辑矛盾,因此 \(u\) 无法确定 \(U_u \ne \emptyset\),第 1 天不离开。
  • 阶段性公共知识沉淀:
    第 1 天没有任何人离开 \(\iff\) 全天下所有人的已知咒语集都非空(\(\forall x, S_x \ne \emptyset\))成为全员公共知识。

2. 归纳假设(Inductive Hypothesis)

假设对于任意整数 \(r < k\):

前 \(r\) 天没有人离开 \(\iff\) 任意大小 \(\le r\) 的贤者子集,其咒语交集均非空:

\[\forall \{x_1, x_2, \dots, x_r\}, \quad \bigcap_{i=1}^r S_{x_i} \ne \emptyset \]

且“任意 \(\le r\) 个人的咒语交集非空”在第 \(r\) 天过后已成为全员的公共知识。


3. 归纳递推:第 \(k\) 天的推理过程

设前 \(k-1\) 天均无人离开。在第 \(k\) 天午夜,贤者 \(a_1\) 开始进行推导:

\(a_1\) 设立反证假设:“假设我知道全部咒语,即 \(E = S_{a_1}\)”。

在 \(a_1\) 脑海中构建的这个虚拟世界 \(W\) 中:

  • 全天下的咒语全集就是 \(S_{a_1}\)。
  • 因此,对于其他任意贤者 \(x\),在世界 \(W\) 中所能掌握的咒语集只能是真实咒语与 \(S_{a_1}\) 的交集,即:

    \[S_x^{(W)} = S_x \cap S_{a_1} \]

现在 \(a_1\) 基于第 \(k-1\) 天沉淀的公共知识,来推演虚拟世界 \(W\) 中前 \(k-1\) 天会发生什么:

场景 A:存在另外 \(k-1\) 个人 \(\{a_2, a_3, \dots, a_k\}\),使得 \(\bigcap_{i=1}^k S_{a_i} = \emptyset\)
  • 在 \(a_1\) 的虚拟世界 \(W\) 中,这 \(k-1\) 个人的咒语集合交集为:

    \[\bigcap_{i=2}^k S_{a_i}^{(W)} = \bigcap_{i=2}^k (S_{a_i} \cap S_{a_1}) = \bigcap_{i=1}^k S_{a_i} = \emptyset \]

  • 也就是说,在 \(a_1\) 假设的世界里,存在 \(k-1\) 个人,他们掌握的咒语交集为空!
  • 根据归纳假设,在虚拟世界 \(W\) 中,这 \(k-1\) 个人必然会在第 \(k-1\) 天(或更早)发现矛盾并离开。
  • 产生矛盾:客观现实中,前 \(k-1\) 天没有任何人离开!
  • 得出结论:现实否定了虚拟世界 \(W\),即假设 \(E = S_{a_1}\) 必定错误!\(a_1\) 严格证明了 \(U_{a_1} \ne \emptyset\),因此 \(a_1\) 必须在第 \(k\) 天离开。
  • 同理,由对称性可知,\(a_2, a_3, \dots, a_k\) 中的每一个人也都能独立完成上述推导,因此他们都会在第 \(k\) 天离开。
场景 B:对于包含 \(a_1\) 的任意 \(k\) 元组,交集均非空(\(\bigcap_{i=1}^k S_{a_i} \ne \emptyset\))
  • 这意味着在 \(a_1\) 假设的世界 \(W\) 中,任意 \(k-1\) 个人的已知咒语交集 \(\bigcap_{i=2}^k S_{a_i}^{(W)} \ne \emptyset\)。
  • 根据归纳假设,在世界 \(W\) 中,前 \(k-1\) 天本来就不会有任何人离开。
  • 无法产生矛盾:世界 \(W\) 的推演结果与“前 \(k-1\) 天没人离开”的现实完全一致。
  • 得出结论:\(a_1\) 无法推翻假设 \(E = S_{a_1}\),即 \(a_1\) 无法证明存在自己不知道的咒语。因此 \(a_1\) 在第 \(k\) 天绝不可能离开。

三、结论总结与图论对应

综合上述归纳:

  1. 必要性成立:如果贤者 \(a_1, a_2, \dots, a_k\) 在第 \(k\) 天离开,那么在第 \(k-1\) 天结束时他们必须能构造出矛盾,这必然要求这 \(k\) 个人的已知咒语交集为空:

    \[\bigcap_{i=1}^k S_{a_i} = \emptyset \]

  2. 转化为最小点覆盖问题(德·摩根定律):

    \[\bigcap_{i=1}^k S_{a_i} = \emptyset \iff \bigcup_{i=1}^k (E \setminus S_{a_i}) = E \iff \bigcup_{i=1}^k U_{a_i} = E \]

    因为每条咒语恰好只有 2 个人不知道(对应图中的一条无向边),\(U_{a_i}\) 即为点 \(a_i\) 所连的所有边。
    \(\bigcup_{i=1}^k U_{a_i} = E\) 恰好说明 集合 \(\{a_1, a_2, \dots, a_k\}\) 覆盖了图中的所有边(即图的一个点覆盖)。

    因此,“最早在第 \(d\) 天有人离开”等价于图的最小点覆盖大小为 \(d\);而在第 \(d\) 天离开的人,正是所有大小为 \(d\) 的最小点覆盖中所包含节点的并集。

10.18

P9060 [Ynoi2002] Goedel Machine

做法

\[\sum_{i=2}^{\sqrt n}[i\text{是质数}]\log_{i}n=\dfrac{4\sqrt n}{\log n} \]

\[\sum_{p=2}^x[p\text{是质数}]\dfrac{1}{\log p}=\dfrac{x}{(\log x)^2} \]

10.23

P7906 [Ynoi2005] rpxleqxq

题目描述

给定序列 \(a\) 和一个常数 \(x\),\(m\) 次询问每次给出一个区间,求这个区间中满足 \(i<j\wedge a_i\oplus a_j\leq x\) 的点对 \((i,j)\) 的数量。

做法

莫队二次离线,这里只说明怎么求一个集合中有几个数和 \(v\) 的异或和小于等于 \(x\)。

由于二离莫队插入 \(\mathcal O(n)\) 次,查询 \(n\sqrt m\) 次。需要 \(\mathcal O(\sqrt n)-\mathcal O(1)\) 的数据结构。

一开始想到的是 \(\mathcal O(\log V)-\mathcal O(\log V)\) 的 trie 树,显然不可行。

我写的是值域分块,或者说是高低位拆位,记 \(w_a\) 为 \(w\) 的高九位,\(w_b\) 为 \(w\) 的低九位。那么 \(p<q\) 等价于 \(p_a<q_a\) 或 \(p_a=q_a\wedge p_b<q_b\),将 \(x\) 加加转为严格小于。令当前加入 \(u\),假设后来查询 \(v\),令 \(w=u\oplus v\),那么 \(\forall v=w\oplus u,0\leq w<x\) 都会增加一的贡献,用高低位表示,就是 \(\forall v,v_a=w_a\oplus u_a,0\leq w_a<x_a\) 和 \(\forall v,v=w\oplus u,w_a=x_a\wedge w_b<x_b\) 会增加一的贡献。直接用暴力枚举 \(w_a,w_b\),用两个数组存 \(v\) 得到的贡献即可。

P5524 [Ynoi2012] NOIP2015 充满了希望

P4690 [Ynoi Easy Round 2016] 镜中的昆虫

P3206 [HNOI2010] 城市建设

根本就没有这么神仙的题目😭😭😭

10.26

计数专题

AT_abc423_f [ABC423F] Loud Cicada

AT_abc309_g [ABC309G] Ban Permutation

posted @ 2026-10-08 14:49  Tanliu  阅读(7)  评论(0)    收藏  举报