杨表的构造与基本性质
前言
挺久以前就听说过的一个算法,但一直没怎么看懂(主要是因为一直没静心去看)。
这次先学了一部分,后面从钩子定理开始的部分暂时没啥心情看下去了,因此就先记录前面这些内容吧。
参考了袁方舟的论文《浅谈杨氏矩阵在信息学竞赛中的应用 》。
杨图及杨表的定义
假设有一个\(n\)的整数拆分\(\lambda=(\lambda_1,\lambda_2,...,\lambda_m)\)(即\(\sum_{i=1}^m\lambda_i=n\)),满足\(\forall i\in[1,m),\lambda_i\ge\lambda_{i+1}\)。
则一个形状为\(\lambda\)的杨图就是一个共\(m\)行,第\(i\)行有\(\lambda_i\)列的表格。
一个形状为\(\lambda\)的标准杨表,就是将\(1\sim n\)不重不漏填入杨图中,并满足每行从左往右递增,每列从上往下递增。
而非标准样表则是将任意\(n\)个数填入,满足每行从左往右非严格递增,每列从上往下严格递增。(其实也可以每行从左往右严格递增,每列从上往下非严格递增)
杨表的构造算法
插入算法
分为行插入和列插入两种,分别表示将一个数从杨表的第一行和第一列插入。由于二者类似,这里仅以行插入为例。
假设我们当前插入的数为\(v\),正在尝试插入第\(i\)行(初始\(i=1\)):
- 如果第\(i\)行为空或者第\(i\)行最后一个数小于\(v\),就把\(v\)放在这一行最后。
- 否则,找到这一行最小的大于\(v\)的数(可以利用\(lower\_bound\)),交换\(v\)和这个数,并将\(i\)加\(1\)移步到下一行。
这个操作非常眼熟,实际上我们平时求最长上升子序列的过程就是维护出了杨表的第一行。(关于最长上升子序列和杨表的关系在之后会专门提及,这里暂且不提)
最后我们记录下插至位置\((x,y)\),十分显然\((x,y)\)一定在边角上。
我们想要证明一次插入算法后得到的依旧是一个杨表。
首先证明依旧满足\(\forall i\in[1,m),\lambda_i\ge\lambda_{i+1}\)。因为插入一个元素只会引起一行的列数发生变化,只要考虑相邻两行列数相等的情况,根据杨表的性质此时第二行最后一列的数一定是这两行中最大的。如果\(v\)无法插入在第一行末尾(\(v\)小于第一行最后一列的数),则无论与谁交换都不可能大于第二行最后一列的数,也就不可能插在第二行末尾。
然后证明单调性,其中行递增显然依旧成立。而注意到由于原杨表满足列递增,且每次替换之后只会往下方或左下方走,所以列递增也依旧成立。
综上,一次插入算法后得到的依旧是一个杨表。
删除算法
删除算法是指把一个边角上的格子\((x,y)\)从杨表中删去。
假设我们当前拿着的数是\(v\)(初始为\((x,y)\)位置上的数),正在第\(i\)行(初始\(i=x\)):
- 如果当前是第一行,直接结束。
- 否则,找到上一行最大的小于\(v\)的数,交换\(v\)和这个数,令\(i\)减\(1\)移步到上一行。
实际上是一次插入算法的撤销,即如果我们上次插入算法最终插至\((x,y)\),则我们执行删除算法删去\((x,y)\)之后杨表将变回插入前的样子。
记录表
我们把一个排列中的数依次插入一个初始为空的杨表\(P\),假设对\(p_i\)执行插入算法最终插至\((x,y)\),就在记录表\(Q\)的\((x,y)\)上填入\(i\)。
显然,记录表\(Q\)是一个与\(P\)形状相同的杨表。
一个杨表及其记录表可以还原出这个排列,即一对形状相同的标准杨表与一个排列一一对应。
具体还原就是从大往小枚举\(i\),找到\(Q\)中\(i\)所在的位置,对\(P\)中对应位置执行删除操作,返回值就是\(p_i\)。
杨表与最长上升子序列
杨表与\(LIS\)和\(LDS\)
我们先前就已经提到过,一个序列\(X\)对应杨表\(P_X\)的第一行长度就是\(X\)的\(LIS\)长度。
这里再介绍一个重要性质:设\(X^R\)为\(X\)的翻转,则\(P_{X^R}\)由\(P_X\)交换行列得到。
(实际上有一个类似的性质:运算符取反,则\(P_{X}'\)与\(P_X\)形状上交换行列,但值就不一样了。二者要注意区分。)
利用这个重要性质,由于\(X^R\)的上升子序列是\(X\)的下降子序列,因此我们可以得出一个新结论:一个序列\(X\)对应杨表\(P_X\)的第一列长度就是\(X\)的\(LDS\)长度。
杨表与\(k-LIS\)
\(k-LIS\)表示\(X\)最长的满足\(LIS\)长度不超过\(k\)的子序列。
发现\(1-LIS\)长度(即\(LDS\))是杨表第一列长度,因此可以猜测\(k-LIS\)长度是杨表前\(k\)列长度之和。
同理,\(k-LDS\)长度是杨表前\(k\)行长度之和。
证明考虑\(Dilworth\)定理,一个序列的\(LIS\)长度等于将它分成\(LDS\)的最少数量,因此\(k-LIS\)就应当是前\(k\)列的长度之和了。
例题
容易发现,若要直接维护整张杨表,单次插入的最劣复杂度是\(O(nlogn)\)的,效率极低。
这道题就给我们提供了一个不错的应对方案:利用运算符取反则杨表形状上交换行列的性质,只要维护好运算符取反后杨表的前\(\sqrt n\)行(与原杨表形状上行列交换,因此对应长度就是原杨表前\(\sqrt n\)列的长度),以及原杨表的前\(\sqrt n\)行(求大于\(\sqrt n\)的列长度,必然是完整的),就可以得知整张杨表的列长度了。