Priority Queue 家族

AT 有三道以 Priority Queue 为前缀命名的题目,谁也不会想到一个甚至在 STL 都有实现的一个常见数据结构在 AT 上能有三道专属于它的题目。

ARC127E Priority Queue

给出一个由 \(A+B\) 个整数 \((X_1,X_2,\cdots,X_{A+B})\) 组成的序列,其中包含恰好 \(A\) 个一和恰好 \(B\) 个二。
斯努克有一个最初为空的集合 \(s\) 。他要进行 \(A+B\) 次运算。 \(i\) 次操作如下。

  • 如果 \(X_i=1\) :选择 \(v\) 这样的整数 \(1 \leq v \leq A\) ,并将其加入 \(s\)。这里的 \(v\) 不能是之前操作中选择的整数。
  • 如果 \(X_i=2\) :从 \(s\) 中删除值最大的元素。输入信息保证 \(s\) 在操作前不是空的。

有多少个集合可以成为 \(s\) 的最终状态?求模数 \(998244353\)
\(1\leq B\leq A\leq 5000\)

考虑我们去找出一个集合可以成为答案的充要条件。集合的充要条件其实很多时候不好刻画,所以要么是与另外一个集合产生关系,要么是集合内部的元素需要满足一个关系。而这道题显然集合内部是没有任何限制的,我们只能用另外一个集合来刻画这个集合。

首先让我们考虑一个集合到另外一个集合的过程。不难发现一个集合内的数可以任意替换成大于原数且不在原集合内的数。放到操作序列上看就是交换这两个数的加入顺序,易证交换一定导向这样的改变。所以我们可以考虑找到一些集合使得这些集合能通过只能选每个数都比它大的集合的方式(这里把集合看做一个升序的序列)来限制可达集合。容易发现一种构造是按 \(1\sim A\) 填入集合,最后得到的集合就是所有数都是最小的集合,这是一个类似于贪心的思路。

所以构造一个这样的集合,我们只需要计算出有多少集合使得每个数都大于它中的每个数。这个可以把集合看做一个升序序列防止算重,然后就是经典 DP:设 \(f_{i,j}\) 为目前选到第 \(i\) 个位置,目前选了 \(j\) 这个数。前缀和优化即可。时间复杂度 \(O(AB)\)

ARC139D Priority Queue 2

给你一个包含 \(N\) 个元素的多整数集合: \(A=\lbrace A_1,A_2,\cdots,A_N \rbrace\) .保证 \(A\) 中的每个元素都在 \(1\)\(M\)(含)之间。
让我们重复下面的操作 \(K\) 次。

  • \(1\)\(M\)(含)之间选择一个整数,并将其添加到 \(A\) 。然后,删除 \(A\) 中的 \(X\) -th 最小值。

这里, \(A\) 中的 \(X\) -th 最小值是按照非递减顺序排序的 \(A\) 元素序列中排在最前面的 \(X\) 个值。
\(1\)\(M\) 之间,有 \(M^K\) 种方法可以选择一个整数 \(K\) 次。假设在每种方法中,我们都求出了相应选择运算后 \(A\) 中元素的和。求计算出的 \(M^K\) 个和的和与 \(998244353\) 取模。
\(1\leq N,K\leq 2000\)

其实我们最开始一定有一个思路,就是考虑删掉 \(A\) 中的哪个区间中的元素,用一个类似于区间 DP 的递推来解决。但是这种做法要么贡献很难算,要么转移不能 \(O(1)\)。我们实际上有一种拆贡献很好做的一种方法。

区间 DP 有二维的限制,考虑将限制弱化,拆成一维的限制,同时改变贡献形式。考虑我们把这个和的和拆成对于每个集合,计算 \(\sum_i\sum_x[a_x\geq i]\) 的和。

接下来我们就只需要计算对于每个 \(i\),所有集合中有多少个数大于等于它。这是一个一维的限制,就好做多了。考虑枚举加入了多少个大于等于 \(i\) 的数,做一些分类讨论,然后再乘上其贡献即可。时间复杂度 \(O(NK\log N)\)

UTPC2023P Priority Queue 3

最喜欢的一集。

给定长度为 \(N+M\) 的字符串 \(S\)\(N\) +\(M\) - 组成,以及由 \(M\) 个整数组成的集合 \(A=\lbrace A_1,A_2,\dots,A_M\rbrace\)
考虑集合 \(X=\lbrace \rbrace,Y=\lbrace \rbrace\) ,按顺序 \(i=1,2,\dots,N+M\) 做如下运算。

  • 如果 \(S\) 中的 \(i\) 字符是 "+",则从 \(1\)\(N\) 中选择 \(1\) 个不在 \(X,Y\) 中的整数,并将它们添加到 \(X\) 中。
  • 如果 \(S\) 中的 \(i\) 字符为 "-",则从 \(X\) 中删除 \(X\) 中包含的最小整数 \(m\) ,并将 \(m\) 添加到 \(Y\) 中。这些约束条件确保 \(X\) 在操作之前是非空的。

在运算序列中,有 \(N!\) 个可能的加入的操作序列,求完成运算序列后,\(Y=A\) 的加入方式个数模 \(998244353\)
\(1\leq M\leq N\leq 300\)

真的,很厉害。这个题如果给你 DP 状态你就很容易做出来了,但是想到 DP 状态则是困难的。

考虑每个时刻,如果我们想要去选到 \(A\),我们去描述 \(A\) 目前被选了哪些。因为要选最小,所以如果选择了 \(A\) 的一段降序前缀,那么前面的其它元素其实可以随意选,否则一定不能随意选,否则无法到达 \(A\)。这启发我们直接对这个前缀 DP。

\(f_{i,j,k,0/1}\) 表示目前选到第 \(i\) 个,降序排列后,\(a_j\) 之前的都被选了,\(a_j\) 之后的已经被选了 \(k\) 个,\(a_j\) 是否被选,对于后 \(k\) 个选的任意一种集合的方案数。这是一个典型的 MEX-Counting 式 DP。稍微推一下就能出来。但是注意这个题是不用辅助数组的,因为需要辅助转移的点值每次只有 \(O(n)\) 个,可以直接枚举,而 MEX-Counting 有 \(O(n^2)\) 个,直接枚举就爆了。

时间复杂度 \(O(n^3)\)

下次再做一个 LIS 系列。

posted @ 2024-09-07 21:05  xingyu_xuan  阅读(28)  评论(3编辑  收藏  举报