有个表叫杨表(上)
《浅谈杨氏矩阵在信息学竞赛中的应用 袁方舟》膜拜有感
前方高能,非战斗人员请撤离(都是很干的数学概念)
前言
杨表 (Young tableaux),又叫杨氏矩阵,是一个啥都能掺一脚的代数结构。
为了方便讨论,先来点定义。
杨图:令 \(\lambda = (\lambda_1,\lambda_2,\ldots,\lambda_m)\) 满足 \(\lambda_1\ge\lambda_2\ge\ldots\lambda_m\ge 1,n=\sum \lambda_i\)。一个形状为 \(\lambda\) 的杨图是一个表格,第 \(i\) 行有 \(\lambda_i\) 个方格,其坐标分别为 \((i,1)(i,2)\ldots(i,\lambda_i)\)。下图为 \(n=9,\lambda=(4,2,2,1)\) 的杨图。
半标准杨表:将杨图填上数字,满足每行数字单调不减,每列数字单调递增。
标准杨表:将 \(1,2,\ldots,n\) 填入杨图,满足每行、每列数字单调递增。下图为 \(n=9,\lambda=(4,2,2,1)\) 的一种标准杨表。
斜杨图:令 \(\lambda = (\lambda_1,\lambda_2,\ldots,\lambda_m),\mu=(\mu_1,\mu_2,\ldots,\mu_{m'})\),则形状为 \(\lambda/\mu\) 的斜杨图为杨图 \(\lambda\) 中扣去杨图 \(\mu\) 后剩下的部分。下图为 \((9, 7, 5, 1)/(5, 3, 2)\) 的斜杨图。
斜半标准杨表、斜标准杨表:猜都猜得到,不浪费时间了。
杨表的插入操作 / RSK 算法
RSK 算法包括了插入和删除。删除操作其实就是插入反过来,不影响理解杨表就不写了。
想要插入 \(x\) 时,从第一行开始,在当前行中找最小的比 \(x\) 大的数字 \(y\) (upperbound)(其实大于 \(x\) 还是大于等于 \(x\) 要看具体情况),交换 \(x,y\),转到下一行继续操作;若所有数字比 \(x\) 小则把 \(x\) 放在该行末尾并退出(如果超出了杨图的行数,那么杨图行数加 \(1\))
举个 \(\alpha\) 粒子,将 \(3\) 插入下图半标准杨表:
第一行找到 \(5\),变成:
第二行找到 \(6\),变成:
第三行找不到比 \(6\) 大的数字,放到末尾:
可以证明这样操作后仍然满足半标准杨表的定义。
上代码!
vector<int> a[N];
void insert(int x) {
for (int i = 0;; i++) {
auto it = upper_bound(a[i].begin(), a[i].end(), x);
if (it == a[i].end()) {
a[i].push_back(x);
return;
}
swap(x, *it);
}
}
杨表与 LIS
LIS (Longest Increasing Subsequence) 就是广为人知的最长上升子序列(有时是不下降)。杨表之所以能和 LIS 有关,是因为杨表的插入操作,只看其中一行的话,正好是 dp 求 LIS 的算法。(虽然这是废话)
拓展一下,如果要求 \(k\) 个不相交的 LIS,它们的长度之和最大为杨图前 \(k\) 行长度之和,即 \(\lambda_1+\lambda_2+\ldots+\lambda_k\)。不过要注意,杨表前 \(k\) 行并不能告诉我们 LIS 有哪些数。(类似 dp 求 LIS 后那个 dp 数组也无法告诉我们 LIS 有哪些数)
举个 \(\alpha\) 粒子,如果把 \([1,5,3,2,6,7,4]\) 插入到杨表中得到:
显然 \(1,2,4,7\) 不是 LIS,LIS 应该是 \(1,5,6,7/1,3,6,7/1,2,6,7\)。不过长度是相同的。
这题就是求 k-LIS 的题了。但是 \(k\) 没有限制,如果维护的杨表行数太大,朴素的插入算法 \(O(n^2 \log n)\) 肯定过不了。这就需要一个杨表的性质:如果把比较运算反过来(大于变小于等于),插入操作后的杨图和原来的杨图是转置关系(但是杨表和杨表不是转置的,只是形状转置),具体可以看看这题的题解。
话说回来,由于杨表和转置杨表的关系,我们可以得出一个结论,如果杨表的第一行数字个数是最长上升子序列长度,那么第一列数字个数是最长不上升子序列长度。如果某题限制了最长上升子序列长为 \(\alpha\),最长不上升子序列长为 \(\beta\),我们就可以把它和行数为 \(\alpha\),列数为 \(\beta\) 的杨表联系起来。(现在还没用,一一对应的关系在下文会讲)
杨表与排列
我们可以将排列的数字按顺序插入到空杨表中,这样就会得到一个标准杨表。但是这会出现两个排列对应一个杨表的情况,比如排列 \([2,1,3]\) 和排列 \([2,3,1]\) 都会得到杨表 \(\left[\begin{array}{c}1 & 3 \\ 2 \end{array}\right]\),出大问题。
考虑一个排列对应两个杨表,每插入一个数字到杨表 \(A\),我们在杨表 \(B\) 对应位置记录这个数字的下标(下标从 \(1\) 开始)。
可以证明 \(B\) 也是个标准杨表。
举个 \(\alpha\) 粒子,对于排列 \([2,3,1]\),插入 \(2\) 得到:
插入 \(3\) 得到:
插入 \(1\) 得到:
而 \([2,1,3]\) 会得到:
这样,我们就把一个排列和两个标准杨表一一对应了起来。
杨表和对合排列
对合排列是一种特殊的排列,把对合排列当成个置换后,自己乘自己等于单位置换。好理解一点就是 a[a[i]]=i
。
比如 \(\left[\begin{array}{c}1 & 2 & 3 \\ 2 & 1 & 3\end{array}\right]\) 就是个对合置换。
为什么要讲对合排列呢,因为把对合排列对应的两个标准杨表是相等的。这意味着一个对合置换和一个杨表是一一对应的关系。
上篇只是个无聊的铺垫,在下篇中我会好好讲钩子公式和其他组合数学相关内容的。