November Rain

upd on 20260308

这是我生涯最后几个月的总结,我始终觉得我的水平已经卡到这里了,马上就要突破了,但是我没有做到上一个台阶,或者说这也可能只是我的假象,我省选打出了一个非常恶心的成绩,我失败了,就像无数次那样。这篇文章只不过是一个失败者想要留下来的一些东西,大家可以选择性的看一下,也许我失败的经验可以帮到你呢?

Cause nothing lasts forever

even cold November Rain

思维要点

自信心

自信心是一切思考的前提,如果你失去了思考的自信心那么你不可能做出来任何一道提。

永远不要在一个做法没有完全做完的时候怀疑正确性,永远要相信直觉和身体的本能

看上去很强的必要条件,相信它是充分的

如果心存疑虑,那就不要发射

QOJ10499. Dopasowanie

在场上想到了 \(O(nmk)\) 的做法,这个时候我的问题就出在:我在排除了这个做法有能乱搞过去的可能性后,我就不知所措了,什么都不知道。我想到了一个类似于每次找 lcp 匹配的流程,但是我当时脑子里面一片混乱,根本没有意识到这个问题的难点在哪里。难点在哪里呢?难点在于:什么时候我贪心的匹配 \(t\) 是成立的,越长越好。此时我们应该考虑钦定某些条件,来强制使得它能够满足最优子结构性质。我在这里就开始大脑空白,最后光荣的获得了 50pts。

实际上其实更不是这样的,而是我在思考这个做法的时候,我就一直在反问这样做对不对?我甚至连一个完整的做法都没有给出,这太蠢了。所以在想一个连成型都没有的做法之前就思考正确性,应该把算法思考完整再来想正确性。我不太好评价这个行为。好像我经常犯这样的问题。

考虑贪心的跳 lcp,此时跳完 lcp 就会遇到三种情况,可以替换,删除或者插入。先从最朴素的做法开始,枚举左端点 \(l\),可以想到设 \(f[i, j]\) 为匹配到了 \(s[l, i]\) 内进行了 \(j\) 次操作能够匹配出来的最远 \(t\) 前缀。考虑正确性,这显然是对的,因为你早晚都要匹配,晚匹配不如现在匹配掉,晚匹配显然不优秀。

然后我们发现这样还是不行,但是注意到最多只会出现 \(k\) 个处理 \(f[i]\) 的断点,或者说 \(|f[i, j] - (i - l + 1)| \le k\)。于是 \(i - l + 1 = f[i, j] + \Delta, |\Delta| \le k\),于是可以发现这个 \(O(nk)\) 个状态里面很多地方没有值。压缩一下,设 \(g[i, j]\)\(s\)\(t\) 长度差为 \(i\),进行了 \(j\) 次操作后 \(t\) 最长匹配可以到哪里。因为这本质上是将 \(f[i, j]\) 中没有值的位置压缩掉了,所以正确性显然有保证。

转移用 lcp 状物转移一下就可以了,时间复杂度 \(O(nk^2)\)

代码好像写起来细节挺多的,我被肘了好几次。

试错过程

对于一道题可能有很多个入手点,那么我们应当的姿态是什么?先把这些入手点给写下来,一个不行就换一个。可能的决策构成一棵树/DAG,于是:

要有一条路走到黑的魄力,更要有在一个“看上去可行的做法实则不可行的时候

  • 寻找不可行的地方,诊断是否致命
  • 如果的确是致命的,那么就换一个做法

我似乎已经在模拟赛中利用过了,但是没有把它内化为自己的身体本能,所以我现在也找不到题目……

找到了。

QOJ16117. XOR-Excluding Sets

很容易把问题划归为对于每一个前缀求解异或和为 \(0\) 的子集数量和大小和。

前言:在场上做这道题的时候,我基本只会线性基板子,只记得结论是 \(2^{n - c}\) 为异或为 \(0\) 的子集数量(\(c\) 为线性基大小),即非主元数量。

直接大胆猜测,对于每一个不在线性基里面的数,可以用线性基里面的异或和表示,同时求解这个使用的集合是简单的。随后我们发现就可以独立出来每一个使用的贡献,从而求解。

这个“求解使用的集合”是简单的是我猜的,我不确定这件事情,但是我们仔细分析一下:首先是线性基内部的每一个数,显然可以维护出来,线性基外的也跟着异或,发现是容易的。

主要就是这个大胆的“猜测”。

如果一点思路都没有

  • 首先,真的是一点思路都没有吗?相信自己的身体本能,相信直觉的力量。
    • 如果心存疑虑,就不要发射。
  • 枚举自己的技术武器。
    • 从大方向到深入枚举。

遇到复杂模型

首先,严格的手玩,严格的体会过程,一定要认真对待。对于复杂的,没有见过的东西,第一件事情就是手玩一下!!!

P7830 [CCO 2021] Through Another Maze Darkly

对于一个点,第一次遇到它后,接着会走它儿子部分的一段前缀,从父亲返回。以后再遍历到这个点就是所有儿子都会遍历到。当所有点被标记,那么就会进入欧拉序的循环。

形式化的说,遍历欧拉序。首先找到一个当前没有被经过的点 \(i\),它一个儿子的前缀会被取到,这一部分一定也没有被取过,所以往里面递归,记录时间,然后跳出这个子树,寻找下一个没有被经过的点,以此类推,直到这个欧拉序被完全遍历,如果没有那么就一直进行下去。

记录这个同时计算时间。

写的代码参考了题解的,因为我觉得它写的很简洁优美。把所有的放到一个递归函数里面。

void work(int now, ll tim, int qt) {
	int u = dfn[now];
	if(tag[now]) {
		for(int i = 0; i < pos[u].size(); i++)
			del(pos[u][i]);
		while(qt <= m && Q[qt].val == tim)
			ans[Q[qt].ind] = u, qt++;
		if(gra[u].size() == 1) work(gra[u][0], tim + 1, qt);
		else work(gra[u][1], tim + 1, qt);
	}
	else {
		int w = Find(now);
		if(!tag[w]) {
			while(qt <= m)
				ans[Q[qt].ind] = getl(now, Q[qt].val - tim), qt++;
			return ;
		}
		int dist = dis(now, w);
		while(qt <= m && Q[qt].val < tim + dist)
			ans[Q[qt].ind] = getl(now, Q[qt].val - tim), qt++;
		work(w, tim + dist, qt);
	}
}

对于 tag[u] = 1,即这个点没有被标记过,只找下一个位置。因为如果下一个位置没有遍历过就遍历,如果遍历过,子树内可能没有遍历完,如果遍历完了那么在出这个子树的时候自然也会到 \(u\) 的下一个儿子。总之是按照一个欧拉序转移的。

考场上我是在最后手玩链的时候模糊的感受到了这一点。但是还是没有完整的提出,最后没有写出来。我太懒惰了,没有及时手玩,这就是问题。

及时排除不可能的做法

对于某些特殊问题(比如最大独立集),如果划归到这类问题,那么显然可以考虑找性质而不是继续研究这个不可能做法。

但是有一类做法是没有这些众所周知的结论的。

鉴定一种做法不可能,一般是:这样想太复杂了,不太可能。或者说就是,如果你往一个方向想了 20min 后仍然一无所获,那么 90% 这题压根不是这个做法。及时放弃才是好选择。

P10104 [GDKOI2023 提高组] 异或图

我自己做的时候对于求解异或和为 \(0\) 方案数部分想了很久的集合幂级数……我必须承认这一点。

一般分析方法

考虑一般模型

对于一部分问题,我们拥有一个比较一般的,已经有成熟做法的模型,那么我们就先不考虑题目中可能的特殊性质,从这个一般模型出发,再来求解。这样的话我们就可以找到一个解决问题的抓手。

有一个有趣的创造者悖论,那就是有时候一个更加宏观的问题往往更好解决,这并不是偶然,因为对宏观问题的入手,往往代表着你已经深入了解了这个问题的结构。

例子:

P9169 [省选联考 2023] 过河卒

实际上只有三个点位置,所以盘面可以用六元组代表坐标,这是 \(O(n^6)\) 级别的,点数和边数同阶,为 DAG。

问题转化为在这个有向图上有一个棋子,某些点位是终止点位。获胜规则为:在终止点位上,当前手获胜;如果一个点没有出边那么必败。选择的策略是:当前手如果必胜,那么会尽可能希望行走步数少;如果先手必败,那么会尽可能希望行走步数多。

首先考虑判定必胜和必败态。经典的在 DAG 建立反图然后 dp 即可,\(f_u\) 为从 \(u\) 出发必胜/必败,然后直接转移。对于路径长度限制,注意到 bfs 反图就是按照最短路径分层的,所以对于必胜态用第一个后手必败点,必败态用最后一个后手必胜点即可,转移很自然。

总结一下,这道题我们首先分析题目转化成了很经典的,一般化的博弈论模型,然后就做完了!而且甚至一点特殊性质没有用!

CF2097F Lost Luggage

这题我没过主要是因为我被卡常了,这题思路还是挺简单的。

建立网络流模型,问题变为网络流最大流。这是一个经典的问题:分层图网络流最大流,我们考虑求解最小割,然后用状压 dp 维护连通性即可。

CF1110H Modest Substrings

很经典的 acam 上 dp,acam 过于庞大,所以对于满 trie 位置,我们可以压缩起来直接求解。

特别的要注意,这里从某种角度并不是简化了 acam 的结构,而是我们把贡献分成了两部分来计算。

结合几何图形

这是一个在扫描线中我写过的技巧,利用几何图形刻画题目条件,有的时候我们就可以成功的将困难的,不形象的条件判定转化为清晰的,容易刻画的条件,再利用各种方法求解。

很经典的应用是:将序列 \(p\) 的偏序关系用 \((i, p_i)\) 之间的点对关系进行刻画;利用凸包性质进行一些刻画。

QOJ13008 Lines Game

回到题目,因为不能重复删除,所以很显然删除的集合 \(S\)\((i, p_i)\) 应当不存在逆序对。考虑判定怎样的集合是合法的,如果和 \(S\) 中一个点形成逆序对,那么就不合法。画到二维平面上,\((i, p_i)\) 作为一个点,形成逆序对说明在划分出的第二或者第四象限,那么最终 \(S\) 就会形成一个在一三象限这根轴上面走的集合,要求这根轴上面不能加入其它点,即 \(S\) 是极大的。这个可以用相邻两个 \(i\) 之间,平面的矩形中没有任何点刻画。

接下来就是对暴力 dp 的优化。如果以线性为阶段依次转移,那么就可以直接上 segbeat,这里面也有一些思考的手段在。

QOJ7649 序列

如何刻画没有 120 形态的序列?

考察这个 \(1\) 是怎么样和后面的 \(2, 0\) 形成约束的。

考察 \(a_i > a_k\) 这件事情,这要求其中的 \(a_j\) 均在小于等于 \(a_i\),发现此时刻画起来还是很吃力;再来考察 \(a_i < a_j\) 这件事情,此时要求所有后面的 \(a_k\) 都大于等于 \(a_i\)。此时我们用代数手段已经非常难以刻画了,于是使用几何手段,将序列投射到 \((i, a_i)\) 的数点上面,那么就可以这样刻画:

提取出每一个前缀严格 max 上的点,那么可以发现构成若干个矩形,这样的矩形内部也是要求满足上述的,单个矩形内部可以通过删除第一个点然后继续分型继续计算,然后和上面部分合并,这样递归下去,可以得到一个计数方法。

entertainment-1

对于序列 \(a_i\),每次询问 \(k\),构造序列 \(b_i \gets a_i + ki\),求 \(\max\{b_i\}\)

值得注意的是,在连续情况下这个等价于将一个函数的导数集体加 \(k\) 后积起来。我不太懂这个东西有没有连续函数下的高妙意义,因为我没有严肃学习过这部分内容。

回到这个问题,直接从代数手段,只能得到差分序列相加,但是用差分序列直接前缀和还原是没有前途,没办法做的。于是考虑几何角度(刚刚的连续情况其实可以启发这一点),然后发现候选点一定在一个凸壳上,然后就做完了。

找代表元

尤其在计数问题(因为要对计数结构进行优秀刻画)的时候。总之,我们经常需要用一个代表元刻画一个结构。

怎么样找代表元呢?

  • 至少在计数问题中,代表元应当是唯一的。
  • 代表元应当是容易求解的。

其实从中我们也可以反思一下对计数问题的解决,或者说对结构的判定。在 QOJ7649 这道题中,我们是利用递归结构来判定的;而在另外一些问题中,我们是找代表元,或是找充要条件来判定的。

CF1210F1/2 Marek and Matching

深刻,高级。

用 Hall 定理来刻画是烂大街的,问题在于如何刻画 \(V_T - \max\limits_{T\subseteq S}(|T| - |N(T)|)\)

证明可以详见我的题解,我们可以证明满足 \(|T|\) 最小的取得 \(\max\limits_{T\subseteq S} (|T| - |N(T)|)\)\(T\) 唯一。代表元不具有最优子结构,所以我们考虑正难则反。设 \(f[S, T]\) 为对于 \(S\)\(N(S) = T\) 有完美匹配的概率,\(g[S, T]\)\(S\) 的代表元为 \(T\) 的概率,转移不是本文重点略去。

QOJ4812. Counting Sequence

不难想到这个问题是根号分治。我分析的时候出了问题,因为我是用 \(\max\{a\}\) 作为代表元,但是条件放宽到 \(a_1\) 做代表元是完全可行的。\(\max\{a\}\) 刻画难度显然高于 \(a_1\) 的刻画难度。

转换视角

所谓转换视角,就是一个方向行不通我们换一个方向,一个常见的换方向就是“反方向思考”。很难删除做?我们考虑加入!很难正着扫描?我们倒着扫描!

B5567 点分树

很直观的思想就是:判定一颗树 \(T\) 是否是 \(T_0\) 的点分树,对于 \(T\) 从根到下,依次删除点 \(u\) 得到的连通块在原图中是极大的连通块。

分析这个条件为什么难,“依次删除”是一个动态的过程,“极大”同时不好判定。我们希望将这个条件变得简单一点,更容易判定,同时仍然充分。

“极大”真的需要吗?是不是只要联通即可?并非如此。现在我们转换一下视角,删除点 \(u\) 得到极大连通块,所以我们考虑从每个点不断连接构成原树,此时是“只要联通即可”。对于点分树上点 \(u\) 到点 \(v\) 的连边,能构成这条连边的条件就是原树上 \(u\)\(v\) 上所有点均在点分树中较深的子树内部(除了开头的那个点)。点分树钦定 \(1\) 为根,我们可以利用这个方法判定点分树上 $u,v $ 两点可能的父子关系。

反思一下这个流程,我们发现从点分树角度判定,不断“删除”太难了,然后我们就考虑:如果是加入一条点分树上的边呢?这个时候充要条件就产生了。这就是转换视角的魅力。

CF1810G The Maximum Prefix

容易想到一个暴力 dp,设 \(f[i, j, k]\) 为长度为 \(i\) 的序列,前缀和为 \(j\),最大前缀和为 \(k\)。直接转移,是 \(O(n^3)\) 的,拼尽全力无法战胜。

这过程中暗含了一个“模拟对数空间的图灵机”的过程,从左到右扫描一遍这个序列,求解最大前缀和必须要记录 \(max\)\(summax\) 两个量,再算上阶段,此时无可避免的要涉及到 \(O(n^3)\) 的情况。

我们能够仅仅使用一个额外变量来计算最大前缀和吗?实际上是可以的!正着不行,考虑倒着,设上一轮的最大前缀和为 \(maxsum\),那么 \(maxsum\gets \max(0, a_i + maxsum)\)。如此就只用一个了!

接下来怎么 dp 呢?从后往前 dp 吗?这样我们就没办法对于每一个前缀求解了,仍然考虑从前往后 dp,利用提前钦定的思路,将后面部分的 \(maxsum\) 钦定为 \(j\),设 \(f[i, j]\) 为长度为 \(i\) 的前缀,后缀最值为 \(maxsum\) 的结果。提前钦定也是非常重要的 trick,下文会详细展开一下。

分部分解决

zxx 哥哥总是在题解中把一道题拆分成几个部分分开解决,我也应该学习伟大的 zxx 哥哥。

P8935 [JRKSJ R7] 茎

把问题分 part 解决,很显然除了 \(1\sim m\) 这条链上,外面的删除是相对自由的,可以直接用一个树上背包维护,而链上则需要单独 dp。前一个部分作为后一个部分求解的系数。这两部分几乎是完全独立的,所以可以分别求解。

做题的时候要有这样分开的意识!

寻找不变量

P7951 [✗✓OI R1] 右方之火(节选)

对于树的情况充要条件分析。

我都不会菊花图我能会这个吗(流泪。

找到一个度数大于等于 \(3\) 的节点为根,如果不存在说明是链,直接做。然后不断修改 \((x, fat_x, fat_{fat_x})\) 这个三元组,使得只剩下根这个菊花不为 \(0\),做菊花。

通常来说,对于一个看上去很对的构造方法,我们要相信它就是充分的。尝试证明。

首先分析一下这个构造方式的本质是什么。此时我们只在乎每个值 \(\bmod 2\) 后的结果。修改 \((x, fat_x, fat_{fat_x})\) 即给 \(x, fat_{fat_x}\) 异或上 \(s_x\)。观察不变量,发现树黑白染色后,黑点异或值和白点异或值总是不变。同时这个操作相当于使得根节点为黑点的所有异或值。有解当且仅当黑点异或值为 \(0\)

证明如果黑点异或为 \(1\) 无解即可说明条件的必要性,通过构造即可说明条件的充分性。证明黑点若异或为 \(1\) 无解很简单,因为无论怎么修改集合异或为 \(1\) 说明一定有一个点无法被消为 \(0\),即无解。于是我们成功的证明这样构造合法是最终合法的充要条件。

操作次数只有根没有操作,是 \((n - 1)\) 次。

CF2143E Make Good

咕咕咕。

自由元相关

之前我喊它叫唯一确定的思想,认为是设一些元为常数后,整个盘面唯一确定。不过似乎有更深入的自由元相关的理论,那么就用这个文字吧。

有些问题发现可以采用一些自由元的想法,考虑只确定一部分,然后能不能唯一确定这个盘面?如果产生了不合法的情况,又应该怎样判断?

在线性代数部分的应用主要是分析一些高斯消元的时候,一定要注意秩的大小。

这个思想一个经典的应用就是统计异或和为某个定值的时候使用,接下来会介绍两道这样的题目。

P3214 [HNOI2011] 卡农

经典永流传,伟大无需多言。

形式化题意即给定 \(n\)\(U = \{1, 2, 3, \dots, n\}\),询问有多少种方案选出 \(m\) 个互不相等的非空集合且最终异或和为 \(0\),集合内部有序。

首先只考虑异或为 \(0\),此时可以发现已知前 \((m - 1)\) 个集合就可以唯一确定最后一个集合了,最后一个集合是非自由元,于是这部分就是可以直接计算的。

现在都考虑起来。特别的因为我们每一个方案都考虑了 \(m\) 次最后要除以 \(m\)

前面有 \(\binom{2^n - 1}{m - 1}\) 种。首先剔除最后一个是空集的情况,这部分有 \(f[m - 1]\) 个情况。然后是删除最后一个非空但是和之前某部分相等的情况,这部分是 \(f[m - 2](2^n + 1 - m)\),因为最后选的两个不能和之前重复。

于是可得 \(f[m] = \dfrac{\binom{2^n - 1}{m - 1} - f[m - 1] - (2^n + 1 - m)f[m - 2]}{m}\)

P10104 [GDKOI2023 提高组] 异或图(节选)

沿用了类似的思想。

容斥部分很 trivial 不讨论。

随后回到了最沉重的话题,\(m = 0\) 怎么做?即:

有多少种 \(\{b\}\) 使得:

  • \(\forall i, b_i \le a_i\)
  • \(\oplus_{i = 1}^n b_i = C\)

观察:

  • 这个问题明显不弱于最后异或和为 \(0\),所以我们可以转化成异或和为 \(0\),这样可以方便讨论。转化方式是:在最后增加一个 \(C\),减去最后增加一个 \((C - 1)\) 的方案数。问题变成了 \(C = 0\)
  • 如果没有 \(b_i \le a_i\) 的约束,或者说 \(a_i\) 都相等且为 \(2^k - 1\),那么这是很容易的,如果确定了前面的数,最后一个是唯一的。(P3214 [HNOI2011] 卡农)

直观感受上,首先这个不能集合幂级数,试试也可以知道得到的结果及其猎奇。其次为了维护 \(b_i \le a_i\) 的约束,只能考虑类似于数位 dp 的手法,从高往低做。

对于最高位 \(d\),如果有 \(k\)\(1\),钦定好这一层的选择方式。只要选择将一个 \(1\) 修改为 \(0\)那么总数就可以直接计算。否则全部保留原位,我们需要用下一层的信息。所以可以考虑设 \(f[i, 0/1, 0/1]\) 代表考虑了前 \(i\) 个数,目前有没有将 \(1\) 修改为 \(0\),修改了的奇偶性下所有 \(a'_i + 1\) 的乘积。直接转移即可。

现在我们得到了一个 \(O(n\log V)\) 的做法。

通过唯一确定的方法,我们将问题变得更加自由,从而极度的简化了这题的做法。

从化简版本入手

这个问题真是太难了,于是我们考虑缩减一些条件,然后不断加强。

注意到很多题目我们已经自觉地再使用这个思想模式了。比如计数问题,多个约束那么就先从简单的约束考虑起;比如环问题,就从链问题考虑起;树问题就从菊花和链考虑起。

QOJ5374 数圈

神仙题!

很容易观察到一点,总和不变,因此无解情况应当是总和小于 \(0\)。如果总和恰好等于 \(0\) 但是最终不是全为 \(0\) 也无解,因为根本构造不出来最终情况前一步。

考虑如何刻画。首先环很难,考虑链,发现是交换前缀和。现在是环,可以考虑复制无限分,即构造无穷序列 \(a_i\),有 \(a_i = a_{i\bmod n}\)。链的话求解就是对 \(2\sim (n - 1)\) 部分排序,求逆序对。对于环的话,每次交换相邻两个位置会将所有模 \(n\) 同余下的位置交换,如何计算操作次数?

继续思考性质:因为是无限循环的序列,所以每个循环内一个点往后提供的逆序对数量 \(R_i = \sum\limits_{j > i}[S_j < S_i]\) 中满足 \(R_i = R_{i\bmod n}\)。每次交换 \(S\) 后对每个循环 \(R\) 产生的影响也是相同的。于是根据经典结论,最终答案也是 \(\sum\limits_{j = 0}^{n - 1}R_j\)

\(R_j = \sum\limits_{i < j < i+n}\lfloor\dfrac{S_i - S_j - 1}{S_n}\rfloor + 1 = \sum\limits_{i < j < i + n}\lfloor\dfrac{S_i}{S_n}\rfloor - \lfloor\dfrac{S_j}{S_n}\rfloor + [S_i\bmod n > S_j \bmod n]\)

这是一个三维偏序模型。如果不考虑最后的艾弗森括号就是二维的,先做掉。考虑最后的艾弗森括号,由于存在 \(S_i \bmod n = S_{i + n}\bmod n\) 所以还可以拆成两个二维偏序。最终是 \(O(n\log n)\) 的。

总结:为什么我没有做出来这道题?

  • 首先是我见到这道题我就被唬住了,我怎么可能会这么乱七八糟的操作。
  • 接着是我对环问题的处理:我根本不会处理,根本没有去先考虑链再考虑环。虽然环有的时候存在利于操作的性质,但是更多时候还是不利于操作的性质。因此对于环上问题,最好先试试链的问题。
  • 交换前缀和这样的模型明明很常见啊!P7962 这题是交换差分。

技术板块

接下来就是将分析方法和技术本身进行结合了。这是一些凌乱的东西。我们将用一级标题表示板块,二级标题表示板块下的计数,三级标题表示举例的题目。

最后的做题手段就是枚举所有可能的技术,挨个尝试。所以拥有一个完备的技术库是很有必要的。虽然我到现在还是没有 TAT。

主要集中记录我目前新学到的一些技巧。

计数

Min-Max 容斥

\[\max(S) = \sum\limits_{\empty \subset T\subseteq S}(-1)^{|T| - 1}\min(T)\\ \min(S) = \sum\limits_{\empty \subset T\subseteq S}(-1)^{|T| - 1}\max(T) \]

特别注意这里面 \(T\) 不能为空集,同时 \(T\) 可以等于 \(S\)

证明:

以第一个式子为例,将 \(S\) 内元素从小到大排序,令 \(n = |S|\),对于第 \(i\) 个式子,后面有 \((n - i)\) 个元素,那么它所提供的贡献就是 \(\sum\limits_{j = 0}^{n - i}\binom{n - i}{j}(-1)^j = [n - i = 0]\),当且仅当 \(i = n\) 时会提供 \(n\) 的贡献,即 \(\max(S)\)

由于期望具有线性性,所以这个东西可以直接套用到期望上面。

\[E(\max(S)) = \sum\limits_{\empty \subset T \subseteq S}(-1)^{|T| - 1}E(\min(S))\\ E(\min(S)) = \sum\limits_{\empty \subset T \subseteq S} (-1)^{|T| - 1}E(\max(S)) \]

主要用来算期望,经典的运用在于:做集合覆盖,每一次有概率选择一个集合,询问期望覆盖完的时间,对于 \(E(\max(S))\) 转化成 \(E(\min (S))\) 就相对更容易直接计算。这个东西是比较经典的,主要用于没有思路了然后用来找突破口。kth 的拓展版本似乎用的不太多,这里一并写上。

\[\operatorname{kmax}(S) = \sum\limits_{T\subseteq S, |T| \ge k}(-1)^{|T| - k}\binom{|T| - 1}{k - 1}\min(T)\\ \operatorname{kmin}(S) = \sum\limits_{T\subseteq S, |T| \ge k}(-1)^{|T| -k}\binom{|T| - 1}{k - 1}\max(T) \]

计算局部贡献

特别和 dp 中常用的“均摊贡献”取了不一样的名字。在很多计数问题中,我们针对一步的贡献进行统计,可能会产生非常强大的效果。

QOJ3089. Harsh Comments

既可以用 min-max 容斥的模型,也可以:我们考虑一个人加进来以后产生的贡献。具体我没有研究

P10256 高仿的 Migos

听讲题还听到了另外的做法,对于边 \((i - 1, i)\),考虑它的贡献,对于每一个跨过这条边的的区间,考虑会不会回去,于是期望经过的步数是一个几何级数 \(\dfrac{1}{p_i}\)。现在考虑多个区间在一起,每个区间回不回去是一个独立事件,所以计算乘积就是这条边的贡献。

QOJ7509. 01tree

在杂项里面要记录这个相邻异或的 trick。

考察其中一条连边产生的贡献即可。虽然重点不在于此。

dp

延迟钦定

对于 dp 我们已知的内容是一个前缀,但是需要用到一个后缀的部分,此时我们钦定后缀部分的信息,然后来 dp。

  • P8935
  • CF1810G
  • P8329

这些都是经典的题目。经典的应用比如:

  • 对于 mex 问题,我们只记录最长前缀,在 mex 变化的时候再来统一变化时产生的贡献。

P7213 [JOISC 2020] 最古の遺跡 3

首先考虑充要条件。

显然我们不会选择从值域角度入手,太难了。考虑从下标角度,从后往前。我们可以得到这样一个结论:对于 \([i, n]\) 进行操作直到收敛,然后用这一部分再来和 \((i - 1)\) 操作,那么最终也可以得到正确的结果。证明从略,可以感性感知一下。令 \(h_i'\)\(h_i\) 操作收敛后的结果。

因为我们只关心每一个点删空了没,那么删空的充要条件也就是 \([1, h_i]\) 在后缀 \([i + 1, n]\) 内均完全出现过。利用“延迟钦定”的思想,我们设 \(f[i , j]\) 为对于后缀 \([i, n]\) 内,极长连续前缀 \([1, j]\) 的结果。

如果 \(i\) 被删空了,那么 \(f[i + 1, j]\)\(f[i, j]\) 贡献,令 \([i + 1, n]\) 内已经有 \(c_0\) 个被删空了,于是此时还可以选择的还剩 \((j - c_0)\),即 \((j - c_0)f[i + 1, j]\) 贡献到 \(f[i, j]\)

如果 \(i\) 没有被删空,mex 不变,那么我们延迟计算;如果变化了,那么 \(f[i + 1, k]\)\(f[i, j](k < j)\) 贡献。如果考虑操作后的,那么就是存在 \((j - k)\) 个还没有产生的数,\(h_i\) 最后变为 \((k + 1)\),然后把前面的串起来。对于前面的部分则构成了 \((k + 2)\sim j\)。对于 \(h_i' > j\) 的部分,我们不去管,需要的时候再来求解。我们发现我们根本不关心这两部分之间具体元素之间的相对位置,因为形成的 \(h\) 完全断开。

只考虑 \(h_i' \in [k + 2, j]\) 内的部分。令前面有 \(c_1\) 个没有被删空,其中有 \(k\) 个都是 \(1\sim k\) 内的,于是选择上这部分方案数就是 \(\binom{c_1 - k}{j - k - 1}\)。对于 \(i\) 位置,如果不考虑“每个元素最多被选两次”会有 \(2(k - j)\) 个选法,假设前面已经选完了 \((k - j - 1)\) 个那么此时只剩下 \((k - j + 1)\) 个了。注意到此时我们是将一个数出现的两次看作了不同的元素的,所以最后答案要除以 \(2^n\)。对于剩下部分的 \((j - k - 1)\) 个数,要求就是使用后可以完整的填充 \([j + 2, k]\) 这部分,我们不妨把值域投射到 \([1, j - k - 1]\) 上,此刻问题为:存在 \(m\) 对数,两个 \(1\) 到两个 \(m\),在其中选择一个大小为 \(m\) 的子序列使得用上面的方法操作后是 \(1\sim m\)。设为 \(g[m]\)。此时系数就是 \(\binom{c_1 - k}{j - k - 1}(j - k + 1)g[j - k - 1]\)

考虑 \(g[n]\)。不难发现这是一个很类似的问题。将整个序列拆成两个部分,第一部分是一开始形成 \(1\) 开头的连续段,剩下的就是子问题。令第一部分大小为 \(i\),一共有 \(2i\) 个,前面放了 \((i - 1)\) 个最后剩下 \((i + 1)\) 个可选,然后前面部分连续是 \(g[i - 1]\),后面一部分连续是 \(g[n -i]\)。这两部分加入的相对顺序是 \(\binom{n - 1}{i - 1}\)(因为第一个固定),于是总转移为 $g_n = \sum\limits_{i = 1}^n g[i - 1]g[n - i]\binom{n - 1}{i - 1}(i + 1) $。

再次搞明白这个推导还是花了我很久,依旧没有完全把这道题掌握,到时候再看看吧。

我本人不太理解为什么我们把对于这类类 mex 问题和上面 P8935 内都叫做延迟钦定。对于类 mex 问题,核心思路在于“在改变的时候计算贡献”,而不是贡献均摊(即“费用提前计算”);对于 P8935 等题,关键在于“不知道后缀的信息”,于是我们考虑在状态中记录下后缀信息,这也是广义的费用提前计算。我觉得我们不能把它们混为一谈,但是似乎现在大家普遍是这么看的?那好吧。(瘫

集合幂级数

边双连通-联通变换

卧槽,彻底怒了,用户指出了最核心的矛盾点,我根本没有掌握什么是边双连通-联通变换。我必须承认我根本不会,现在完全不会集合幂级数的乃龙要把比赛给糊弄过去

给定一个图 \(G = (V, E)\),对于一个点集合 \(S\) 存在权 \(f_S\)(一般认为是只有联通块才能产生贡献)。对于 \(g_S\) 定义其权值为:将 \(S\) 进行子集划分为 \(T_1, T_2, \dots, T_m\),产生的权为 \(\prod\limits_{i = 1}^mf_{T_i}c^{m - 1}\) 再乘以将每个集合看作一个连通块,最后形成一张图的方案数,最后对每一个子集划分求和。

你可以把权值看作每一个联通快的贡献乘以每一条边产生 \(c\) 的贡献。我们记得到的集合幂级数 \(G = \operatorname{Trans}(F, c)\)

称后来连边的边为树边。逐点牛顿迭代,每次考虑树边最大的点编号为 \(i\) 的情况,记录这一轮的集合幂级数系数为 \(g_{i, S}\)。如果 \(i\not\in S, g_{i, S} = g_{i - 1, S}\),这很平凡。对于 \(i\in S\),考虑 \(i\) 所在的联通快以及 \(i\) 向外的连边。令 \(i\) 所在联通快为 \(W(i \in W)\),接下来对于 \((S - W)\) 的子集划分为 \(T_1, T_2, \dots, T_k\),每一个子集内部都只能用小于 \(i\) 点编号的来向 \(i\) 连边,这一部分我们记作 \(\operatorname{coef}(T_j, i)\),局部内部是 \(f_{T_j}\),还有常数 \(c\) 的贡献,于是不难得到这样的式子:

\[g_{i, S} = \sum\limits_{W}g_{i - 1, W}\sum\limits_{T_1, T_2, \dots, T_k}\dfrac{\prod_{j = 1}^k g_{i - 1, T_j}\operatorname{coef}(i, T_j)c}{k!} \]

定义 \(h_{i, S} = g_{i - 1, S}\operatorname{coef}(i, T_j)c\),于是就有 \(g_i = g_{i - 1}\times \exp (h)\)

这样推导就叫边双连通-连通变换,时间复杂度 \(O(n^32^n)\)


比较直观上的应用是子图生成树计数,虽然有更优秀的逐点牛迭做法,还有我都用这个了我为啥不直接 matrix-tree 也是一样的(

另外一种高妙运用:

特别的,我们考察一种这样的变换:\(F_S\) 初值为 \(S\) 内的连通图权之和,连通图的权定义为 \(c^{|E'|}\)\(|E'|\) 为这个连通图边数,随后进行 \(G = \operatorname{trans}(F, -c)\),则 \(G_S\)\(S\) 内的边双子图的权之和,权定义仍然是 \(c^{|E'|}\)

证明:考虑如何统计 \(S\) 内的贡献,对于导出子图 \(G'\) 计算权和,如果一条边是割边,那么可能在 \(F_S\) 中提供 \(c\) 的贡献,也可能为树边提供 \((-c)\) 的贡献;如果不是割边那么只能提供 \(c\) 的贡献。对于非割边,提供的贡献是一定的,于是我们只考虑前面这部分,若有 \(t\) 条割边,提供 \(\sum\limits_{i = 0}^{t}\binom{t}{i}((-c)^t c^{t - i}) = [t = 0]\) 的权,于是只有没有割边的子图,才会提供 \(c^{|E|}\) 的贡献。

更为一般的,这种变换可以看作是对 \(\operatorname{trans}(F, c)\) 的逆变换。从这个角度来看很多都可以迎刃而解了。举个例子,对于一般子图的 \(\operatorname{trans}(F, -c)\) 就是边双连通子图计数,因为边双连通子图用树组合出来就是 \(F\) 这个集合幂级数。


P11567 建造军营 II

对于 \(p_i, q_i\) 内部的所有边双全部染黑,除此之外所有边都是白色,一条黑边产生 \(1\),白边产生 \(2\)

首先我们只考虑子图中黑边计数,最后要求产生的联通子图不能包含一堆 \((p, q)\) 有且仅有一个在这个图中,可以直接求出这样的集合幂级数 \(F\)。但是这样的黑子图可能不是极大的,即构成的边双中可能存在一个边双不存在任何任何 \((p, q)\)。于是 \(F' = \operatorname{trans}(F, -1)\),然后将不包含任何 \((p, q)\)\(F'_S\) 赋为 \(0\)

然后考虑白边,类似的操作也是求完 ln 后做 trans,不过 \(c = 2\)。也是因为如果存在 \(p, q\) 那么就不是极大白边所以把这部分去掉得到 \(G'\)

然后答案的集合幂级数为 \(\operatorname{trans}(F + G', 2)\)


数据结构

莫队或二区间合并

莫队和二区间合并都是解决静态序列问题的有力工具。

对于莫队而言是“单点加入局部”,对于二区间则是“单点加入局部”,接着是“局部和局部”的合并。不过无论如何,这都涉及到一个“两个方向”的操作。

对于一类序列询问问题不具有交换律,非常神秘,我们则可以从莫队入手考虑。(甚至可以直接从回滚莫队开始考虑),分析往前加入和往后加入的情况,然后试着改为二区间合并,优化为 log。

这个往往也是没有办法的办法,枚举可能的数据结构方法并且往里面带入。

UOJ749. 【UNR #6】稳健型选手

首先 \(q = 1, l = 1, r = n\) 的问题,尝试判定一组取法合法。

对于 \(\forall 2i \le n\),前缀中 A 至少取了 \(i\) 个,容易归纳法。此时则可以扫描一遍,考虑让先手取得尽可能少,于是维护一个小根堆,每次加入两个,再取出最小的那个。如此可以做到 \(O(n\log n)\)。特别的,做一些特判。首先是区间长度为奇数,此时最后一个一定只能由后手取到,所以下面认为所有区间长度为偶数。其次是这里面因为按照 \(l\) 奇偶性不同,每次加入的一对数不同,所以对 \(l\) 不同奇偶性分开来做。

这个没有优化的空间。对于第四档,我们可以考虑莫队。对于第五档,我们可以考虑猫树分治,但是这都离不开向两个方向的拓展。既然已经解决了固定 \(l\)\(r\) 可以增量计算。反过来也容易解决固定 \(r\)\(l\) 增量计算,类似的把小根堆换成大根堆倒过来做就好了。

可以获得一个 \(O(n\sqrt{q}\log n)\) 的回滚莫队做法,维护区间内部选中的大根堆和没有选中的小根堆,每次拓展两个可以直接用刚才的思路,维护一个小根堆,代表后手选中的;大根堆代表后手没有选中的。每次维护新加入的两个元素选中情况即可。

考虑猫树分治。对于 \([l, mid]\) 的后缀和 \([mid + 1, r]\) 的前缀,我们总是可以容易的维护出选中和未选中的部分。

考虑合并两个部分,此时就会产生本来一部分 \([l, mid]\) 内选中,现在选不上;本来 \([mid + 1, r]\) 内选不上,现在选中了。为什么不会出现 \([l, mid]\) 部分原来选不上现在选上了?因为这部分我们是用大根堆维护后缀的,如果原来的大根堆无法选中,新加上处理 \([mid + 1, r]\) 的大根堆肯定更无法选中,\([mid + 1, r]\) 同理。

\([l, mid]\) 中被替换的集合为 \(S\)\([mid + 1, r]\) 中被替换的集合为 \(T\)。分析性质:

  • \(|S| = |T|\)
  • 无论 \(S\)\(T\) 位置如何,这个取法总是合法。因为根据充要条件,原本合法,现在更改后一定是前缀数量更多,后缀数量更少,所以不会破坏性质。

\(k = |S| = |T|\),可以想到只要维护 \([l, mid]\) 中选中的最小的 \(k\) 个和 \([mid + 1, r]\) 中没有被选中最大的 \(k\) 个即可,约束是 \(\operatorname{kthmin} S < \operatorname{kthmax} T\)。随着 \(k\) 变大,\(\operatorname{kthmin} S\) 变,\(\operatorname{kthmax} T\) 变大,为了使 \(\sum\limits_{x\in T} x - \sum\limits_{y\in S} y\) 尽可能大,我们二分最大的 \(k\) 即可。实现上可以直接使用主席树,最后是 \(O((n + q)\log ^2 n)\) 的。

二分图

最大匹配和 Hall 定理

Hall 定理:最大匹配为 \(|V_L| - \max\limits_{S\subseteq V_L}({|S| - |N(S)|})\)

特别的,对于任意一个集合 \(S\) 内使得 \((|T| - |N(T)|)\) 取得最大值并且 \(|T|\) 最小的 \(T\) 唯一,可以利用这个作为代表元。

Hall 定理题目太多了。

最大匹配和 Koing 定理

你现在遇到了最大匹配,但是 Hall 定理没有好用的出口,此时我们考虑 Koing 定理,即最大匹配等于最小点覆盖。这一个定理经常被遗忘掉。

12-29 模拟赛 T1

左右各有 \(n\) 个点二分图,每一个点拥有一个向量,每个点不同度数产生相应贡献。最多可以 \(m\) 条边,问当二分图最大匹配数量为 \(k\) 时的最大贡献,\(k\in [1, n], n \le m\)

对于一个二分图,已知每个点度数,那么如何刻画可能的最大匹配数量?可能的最大值一定是左边度数非 \(0\) 点数量和右边的取 min,显然。但是可能的最小值呢?我们先抛开这个问题。如果我们知道最小值是 \(L\) 最大值是 \(R\),那么大胆猜测 \([L, R]\) 内都可以被更新到。

(我必须承认我并不会严谨的证明)

对于二分图最大匹配,除了 Hall 定理的刻画,还可以用 Koing 定理最大匹配数=最小点覆盖数!。为什么不是 Hall 定理。Hall 定理因为是“对于所有 \(S\)\(N - \max\{|S| - |N(S)|, 0\}\)”,所以涉及到一一个对于集合 \(S\) 的枚举。通常来说,如果是完美匹配(\(|S|\le |N(S)|\) 是一个比上面求值容易的事情),或者是有一定性质(比如最优的 \(S\) 一定是后缀),那么选择 Hall 定理。但是由于这道题并没有任何有用的性质,而且考虑的“度数”是从“点”的角度出发,“点”覆盖“边”也很容易用度数刻画:如果 \(u\) 在所选点集合,那么和 \(u\) 的连边都被覆盖。优先选择对面没有被选中的点进行覆盖,于是可以得到左部选出来的度数 \(y1\) 和右边选出来的度数 \(y2\) 和要大于等于所选边数 \(j\),只要这样就可以得到一组合法的点匹配数量 \(x1+x2\)

两个部分设 \(f[i, j, k, x, y]\) 为前 \(i\) 个点,总度数为 \(j\),有 \(k\) 个非 \(0\) 度数,有 \(x\) 点被选中作为点覆盖,总度数和为 \(y\),直接 dp 预处理,然后合并即可。复杂度 \(O(n^3m^3)\),我不知道为啥它能过,只能说卡常卡的。

完美匹配的奇偶性

完美匹配数量为这个邻接矩阵的积和式,所以没有 polyn 做法。但是它的奇偶性只和行列式有关,可以直接计算。

图论

优化建图

我已经若干次死在优化建图的手上了。

常见的优化建图手段,对于线性问题,可以考虑前缀优化建图,或者线段树优化建图(处理区间)。对于树上问题,可以考虑用类树上统计方式建图。即树上统计问题的特征在优化建图问题上也适用,毕竟一个道理。比如如果这个问题只和深度有关,即深度相同点等价考虑长剖。如果是距离相关,考虑用点分树来简化结构。特别的,可以考虑虚树如何应用。

树上常见的工具:长链剖分,此时要求深度相同的点等价;点分树,一般用于刻画距离相关的信息,比如压缩“两两距离”的连边。虚树,涉及特定点。dsu on tree 理论上是“在某一个维度上相同的点等价,且这个维度和子树大小同阶”可以用,不过我还没有看到过这样的题目。

GDKOI2025 T2

严肃拷打我的长剖水平。

考虑最短路优化建图,对于第三类点,因为和深度相关,对于一个点 \(u\) 在不同子树中同一深度的点会互相产生贡献,而且这部分点实际上是“等价”的,所以可以想到利用长剖来刻画,把它们放到一个虚点里面。具体在操作的时候,要把虚点拆成两个点,一个入点,一个出点。

首先是对于 \(u\) 合并不同子树内的点。对于一个深度 \(x\) 有很多虚点,我们已经拆成了入点和出点的形式。排成一排,然后对于一个点,它的出点向左边所有入点连边,它的入点被右边所有出点连边,边权为 \(c_d\)。这个部分可以利用前后缀建图优化。

然后是对不同子树之间的合并。全部合并到长链上面去。即将长链的入点向短链的入点连边,断链的出点向长链的出点连边。

首先这道题我做的时候怀疑有什么路径上面的性质,然后我就不会做了。但是这道题正解就是优化建图,其实直接优化建图我还是不会,小丑完了。

QOJ16120. Language Barrier

直接 dp 是 \(O(n^2)\) 的,考虑缩减状态数。观察:

  • 如果 \(1\)\(n\) 区间有交集,那么我们就直接从 \(1\) 走到 \(n\)
  • 无交集,钦定 \(1\)\(n\) 左边,那么每次走一定都会走到右端点,直到有交。
  • 行走过程中只有翻译点和终点有用。

即,行走过程中我们选择 \(1, p_2, p_3, \dots, p_m, n\),能够行走到的要求是两两有交,每次行走的代价是 \(\operatorname{dist}(x, y) + 1\),算上翻译代价,最后 \(-1\)

为了优化建图,浓缩连边信息考虑点分树刻画所有路径。两两有交才能连边,利用线段树优化,这样做是 \(O(n\log^3 n)\) 的。但是注意到第二条性质,每次只会走右端点,所以我们只需要维护一个维度上的偏序关系就行了。时间复杂度就变成了 \(O(n\log^2 n)\)

树上统计

树上统计常用的工具:

  • 边分治,点分治。
    • 通常来说,边分治是点分治的下位平替,因为还要进行一个树的三度化。
    • 但是优势在于只将一棵树划分成了两个集合,在一些情况比点分治处理容易。
  • dsu on tree
    • 要求子树信息和子树大小同阶,即可做到 \(O(n\log n)\) 的总规模进行合并。
  • 虚树。
    • 对于部分点。
  • 数据结构合并。
    • 常用线段树,这个没什么好说的。

有一些题目需要用到边分治/点分治过后来建立虚树,在虚树上再进行分治或者别的手段维护。

详见 https://www.cnblogs.com/thirty-two/p/19524778 这篇文章,这里不再重复了。主要是提一嘴,过一下各种经典做法。

一些经典结论

直径相关:

  • 对于一个点到它最远的点一定是直径的两个端点之一。
    • 证明容易反证。
  • 用一条边合并两个树,那么其直径一定是这 \(4\) 个点中选出来 \(2\) 个。
  • 直径的中点重合。
    • 这一点可以作为计数的基准。

重心相关:这个没什么好说的,不过一些和树的形态相关,划分联通快,并且希望联通快尽可能平均的题目可以试试用树的重心作为根,可能有奇效。比如 P9167 [省选联考 2023] 城市建造

杂项

有一些内容并不是很能归类到数学,数据结构,dp,图论之类的大项目,所以我们把它放到这里。

二进制计算器

不是很清楚这种东西学名叫什么。或者说有没有学名。

对于一类很奇妙和独特的二进制问题,考虑将二进制位先写出来,原本是对于每一行提供的贡献计算,现在我们矩阵转置,用 bitset(或者值域比较小就只用一个数)来维护每一位,从而快速计算贡献。这是一种有些像“计算竖式”的感觉。

这个做法也只能靠着“试用技术”来“试出来”,不太好规定这种方法能够做哪些问题。

P8569 [JRKSJ R6] 第七学区

从或换为与,减一下即可。暴力的做法是对于每一个数位维护它延申几长位 \(1\) 的后缀长度 \(l_j\)。直接做是 \(O(n\log V)\) 的更新。

现在我们来利用这个二进制计算器的思想,把 \(\log V\)\(l_1\sim l_t\) 给列出来。其中将 \(a_i\) 所在的位的 \(l\) 全部加 \(1\),剩余位置全部清零。

完成清零很容易,直接与一下即可。对于 \(+1\),本质为将后缀极长的一段 \(0111\dots 11\) 取反。这部分发现也是可以用位运算直接维护的,就是维护一下当前还剩哪些位置要取反,然后再维护一下 01 位置即可。比较平凡。

P13497 【MX-X14-T7】墓碑密码

前面 fwt 分析部分十分 trivial,都做过一万遍了,直接跳过。

\(cs_T = \sum\limits_{W \in S} [|W \cap T| \bmod 2 = 0]\) 要求 \(0\sim V\) 范围上的全部取值。

考虑增量计算,充分利用 \(cs_{i -1}\)\(cs_i\)。注意到对于 \((i - 1)\)\(i\) 一定是将最后一个后缀全部修改为 \(0\),然后最后一个 \(0\) 修改为 \(1\),即取反一个后缀。

那么产生的变化量也就在这里面。维护一个 \(n\) 行,\(L\) 列的矩阵,每一行都是 \(W\in S\)。提前维护出来对于后缀上若干个列,从和 \(011\dots 1\) 到和 \(100\dots00\) 与出来的差即可求出哪些的 \(|W \in i|\) 奇偶性产生了变化。令原本 \(|W\in i|\bmod 2 = 0\) 部分有一个 bitset,然后修改后将这个 bitset 与上变化位置即可。这部分是 \(O(\dfrac{|V||S|}{w})\),谁能想到 \(\dfrac{|S|}{w} = 2\),真是令人忍俊不禁。

考虑 01 序列

这个已经经典的不能再经典了,但是有的时候还是会忘掉。

题目太多了不放了。

posted @ 2026-03-04 19:58  CatFromMars  阅读(11)  评论(0)    收藏  举报