排列有关 DP/计数

每年都在考,每年都不会。

可能有些转移方程有点小问题,不过不影响整体思路。

排列有关 DP 通常解决方式:

预定(绝对) 插入(相对)
按下标 从左往右逐一确定值 从左往右逐一确定当前值在前缀中的排名
按值 从小到大逐一确定位置 从小到大逐一插入排列

依赖邻项或与下标产生关联的计数问题

可以尝试连续段 DP。

连续段 DP 一般可以将维护的连续段看做游离状态,即我们只需要知道当前状态有多少个连续段,而不在意它们具体位置。因为在连续段合并的时候通常就能够确定某些点的相对位置,而当状态内连续段数量达到下限时,所有点的真实位置也就已经确定了。

简单地,连续段 DP 也可以看做是建笛卡尔树的过程:

  1. 新建叶子节点。
  2. 合并节点。
  3. 成为某个节点的儿子。

CF1515E Phoenix and Computers

发现 \(i\)\(i-1\)\(i+1\) 都被打开的时候必定被打开。这是个邻项依赖的关系。对于连续段 DP,可以尝试定义状态函数 \(f_{i,len}\) 为手动打开了 \(i\) 台电脑,且这些电脑在原位置上构成了 \(len\) 个段的方案数。

那么数量下界是什么?对于自动打开的,因为无论如何都不能手动开,所以在手动打开所有可以开的电脑后统一自动开剩下电脑是一样的。那么对于已知真实位置的一种局面,无法再手动打开电脑当且仅当相邻两个连续段满足 \(r_i-l_i-1=1\)。也就是中间只有一台没被打开的电脑。如果连续段数量为 \(len\),那么这些空位的数量应该是 \(len-1\)。那么对于手动打开 \(i\) 台电脑的下界(其实应该说是上界,但是也可以看做没打开的电脑数量的下界)就是 \(len=n-i+1\)。所以最终答案应该是 \(\sum f_{i,n-i+1}\)

现在考虑转移。通常地,连续段 DP 有三种转移:

  1. 加入新的段。
  2. 加在某一段的两边。
  3. 加在某一段的两边时与另外一个段合并。可以看做是这两个段中间只有一个空位,把空位占了自然就需要合并。

显然这题没有第三种情况。

  1. 加入新的段。\(f_{i,j}=j\times f_{i-1,j-1}\)
  2. 加在某一段的两边。有 \(f_{i,j}=2\times j \times f_{i-1,j}\)

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

P7967 [COCI 2021/2022 #2] Magneti

之前写的,粘过来了。

注意到,对于相邻两个位置的磁铁 \(p_i,p_{i+1}\)。只有当 \(x_{p_{i+1}}-x_{p_i} \ge \max(r_{p_i},r_{p_{i+1}})\) 时两个磁铁才不会相互吸引。

我们把一个磁铁的排列状态极致压缩,保证 \(x_{p_{i+1}}-x_{p_i} = \max(r_{p_i},r_{p_{i+1}})\)。记这样会占用 \(k\) 个位置,那么剩下的 \(l-k\) 个位置就可以在这些磁铁之间随便插了。方案数为 \(C_{l-k}^{n}\)。那么现在我们就只需要维护出在占用 \(k\) 个位置时,极致压缩后磁铁排列的方案数。

不妨将 \(r_i\) 从小到大排序,那么将 \(i\) 插到 \(x,y\) 之间时,代价一定是 \(r_i\)。这样我们就去掉了 \(\max(r_{p_i},r_{p_{i+1}})\) 的限制。

考虑 DP。不难发现,对于第 \(i\) 个磁铁,如果我们放到前 \(i-1\) 个磁铁形成的排列的两端,则会产生 \(r_i\) 的代价。如果我们插到 \(x\)\(y\) 之间,则会产生 \(r_i-\max(r_x,r_y)\) 的代价。前者维护不难,考虑如何维护后者。

这里有个很简单的做法,貌似叫连续段 DP。因为我们插中间会破坏掉原来的结构,那干脆让之前就没有这个结构。形式化的,我们将前 \(i-1\) 个磁铁分成若干个连续的段,那么 \(i\) 插到 \(x,y\) 之间就相当于是合并了两个连续段。只要我们强制让已经合并的两个磁铁之间不再有磁铁插入,就能够保证算法的正确性了。因为这个过程相当于是在倒着维护插入的过程,每次后插入的磁铁合并相邻的磁铁后,前面插入的磁铁就不可能再去破坏了。

定义状态函数 \(f_{i,j,k}\) 表示前 \(i\) 个磁铁,已经形成了 \(j\) 个连续段,且极致压缩后占用了 \(k\) 个位置的方案数。对第 \(i\) 个磁铁进行分类讨论:

  1. 单独形成一个连续段,有:\(f_{i,j,k}\to f_{i,j,k}+f_{i-1,j-1,k}\)
  2. 拼在某个连续段的两边,有:\(f_{i,j,k}\to f_{i,j,k}+2\times j\times f_{i-1,j,k-r_i}\)
  3. 将两个连续段拼起来。因为 \(r_i\) 是目前最大的,所以拼起来的代价将会是 \(2\times r_i\)。有:\(f_{i,j,k}\to f_{i,j,k}+2\times C_{j+1}^2 \times f_{i-1,j+1,k-2\times r_i}\)

那么答案就是 \(\sum\limits_{i=0}^{l-n} f_{n,1,i}\times C_{l-i}^{n}\)。时间复杂度 \(O(n^2l)\)

不知道哪里的题

网上看到的,链接

题意

给定序列 \(a_{1\dots n}\),满足 \(a_i \in \{0,1\}\)。对于 \(k=1\dots n\),求 \(1 \sim n\) 的排列 \(p\) 的数量,满足:

  1. \(p_n=k\)
  2. 对于 \(i \in [1,n-1]\)。若 \(a_{p_i} =1\),则 \(p_i>p_{i+1}\),否则 \(p_i <p_{i+1}\)

保证 \(1 \le n \le 5000\)。答案对大质数 \(mod\) 取模。

邻项产生依赖。

如果没有第一个限制怎么做。从 \(1\sim n\) 插入 \(i\)。对于当前局面中的一个连续段,如果要在两端加入 \(i\),则需要满足:

  1. \(a_i=1\)。可以放左边或右边,放右边的时候需要满足该连续段右边为 \(0\)
  2. \(a_i=0\)。不能放左边,放右边的时候需要满足该连续段右边为 \(0\)

那么可以看做一个连续段的右边必定为 \(0\),也就是说,\(a_i=1\) 只能用来合并(放左边的时候)。定义状态函数 \(f_{i,j}\) 表示加入 \([1,i]\) 后有 \(j\) 段,那么有转移方程:

  1. 加入新的段。条件为 \(a_i=0\)\(f_{i,j}=j\times f_{i-1,j-1}\)
  2. 加在某一段的两边。显然只能加在右边。\(f_{i,j}=j \times f_{i-1,j}\)
  3. 加在某一段的两边时与另外一个段合并。条件为 \(a_i=1\)\(f_{i,j}=2\times C_{j+1}^2 \times f_{i-1,j+1}\)

注意到,如果一个连续段的右边抵到 \(n\) 了,那么这个段的右边实际上是可以是 \(0\) 的。类似于摩天大楼,再维护一位 \(0/1\) 表示是否存在抵到 \(n\) 的连续段即可。答案为 \(f_{n,1,1}\)

如果有第一个限制怎么做。暴力地,\(O(n^3)\) 可以用上面的方法直接做。简单观察,维护 \([1,k-1]\) 分成 \(x\) 个连续段与 \([k+1,n]\) 分成 \(y\) 个连续段的情况。如果把前面 \(x\) 个连续段看成 \(0\),后面 \(y\) 个连续段看成 \(1\)\(k\) 这个点看成 \(2\)。那么一个合法的拼接应该长成:\((0)10101010\dots 01010(1)2\),因为同色连续必定合并。则 \(|x-y|\le 1\)。枚举 \(x\),暴力求方案数就行。维护 \(f_{i,j}\) 表示 \([1,i]\) 分成 \(j\) 个连续段的方案数,\(g_{i,j}\) 表示 \([i,n]\) 分成 \(j\) 个连续段的方案数。例如 \(x=y\) 的时候,方案数就是 \(f_{k-1,x} \times g_{k+1,y} \times 2\)。因为可以 \(0101\dots 01012\) 或者 \(1010\dots 10102\)。其它两种同理。那么枚举 \(x,y\) 的时间复杂度 \(O(n)\),枚举 \(k\) 的时间复杂度 \(O(n)\),预处理 \(f,g\) 的时间复杂度 \(O(n^2)\)。总时间复杂度 \(O(n^2)\)

CF704B Ant Man

  1. \(j<i\)\(x_i-x_j+c_i+b_j\)
  2. \(j>i\)\(x_j-x_i+d_i+a_j\)

\(c_i\) 变成 \(c_i+x_i\)\(b_i\) 变成 \(b_i-x_i\)\(a_i\) 变成 \(a_i+x_i\)\(d_i\) 变成 \(d_i-x_i\)。则:

  1. \(j<i\)\(c_i+b_j\)
  2. \(j>i\)\(d_i+a_j\)

如果记访问的排列为 \(p\),那么这就是个关于 \(p_i,p_{i+1}\) 的分段函数的和的最优化问题。考虑从 \(1\sim n\) 加入 \(i\)。定义状态函数 \(f_{i,j}\) 表示前 \(i\) 个数,分成 \(j\) 个连续段的最小代价。

\(i\) 不是 \(s\)\(e\) 时:

  1. 加入新的段。因为两边连的都一定是比 \(i\) 大的。所以 \(f_{i,j+1}=f_{i-1,j}+b_i+d_i\)
  2. 加在某一段的两边。如果加某段的左边,那么 \(f_{i,j}=f_{i-1,j}+b_i+c_i\)。如果加某一段的右边,那么 \(f_{i,j}=f_{i-1,j}+a_i+d_i\)
  3. 加在某一段的两边时与另外一个段合并。那么 \(f_{i,j}=f_{i-1,j+1}+a_i+c_i\)

\(i=s\) 时:

  1. 加入新的段。因为是开头,所以 \(f_{i,j+1}=f_{i-1,j}+d_i\)
  2. 加在某一段的两边。只能加左边,\(f_{i,j}=f_{i-1,j}+c_i\)
  3. 加在某一段的两边时与另外一个段合并。不可能。

\(i=e\) 时:

  1. 加入新的段。因为是结尾,所以 \(f_{i,j+1}=f_{i-1,j}+b_i\)
  2. 加在某一段的两边。只能加右边,\(f_{i,j}=f_{i-1,j}+a_i\)
  3. 加在某一段的两边时与另外一个段合并。不可能。

最后答案为 \(f_{n,1}\)。时间复杂度 \(O(n^2)\)

需要注意在 \(i=n\) 之前 \(\max(s,e)\) 之后不能合并成一段,还有一些限制比较容易。

AT_abc134_f [ABC134F] Permutation Oddness

这题和连续段真的有关系吗?

先给个比较正常的做法。注意到 \(|i-p_i|=\max(i,p_i)-\min(i,p_i)\)。那么将 \(i=1\dots n\) 看成红色小球,\(p_i=1\dots n\) 看成蓝色小球。并且将它们按照值从小到大排序。则问题就相当于求:红蓝小球配对,配对价值为排在后面的小球的值减去排在前面的小球的值,求有多少种配对方式,使得这 \(n\) 个红蓝小球对的价值和为 \(k\)

定义状态函数 \(f_{i,x,y,s}\) 表示考虑完前 \(i\) 个球,有 \(x\) 个红色小球和 \(i\) 后面的蓝色小球配对,有 \(y\) 个蓝色小球和 \(i\) 后面的红色小球配对,且当前价值和为 \(s\) 的方案数。

  1. 红色小球。
    1. 匹配之前的蓝色小球。\(f_{i,x,y-1,s+v_i}=f_{i-1,x,y,s}\)
    2. 匹配之后的蓝色小球。\(f_{i,x+1,y,s-v_i}=f_{i-1,x,y,s}\)
  2. 蓝色小球。
    1. 匹配之前的红色小球。\(f_{i,x-1,y,s+v_i}=f_{i-1,x,y,s}\)
    2. 匹配之后的红色小球。\(f_{i,x,y+1,s-v_i}=f_{i-1,x,y,s}\)

这样做的时间复杂度 \(O(n^5)\)。已经可以过了。但是像这种配对问题通常有个简单的优化:记 \(cnt_{i,0/1}\) 表示前 \(i\) 个数中,红、蓝小球的数量。那么枚举 \(x\) 就能知道有 \(cnt_{i,0}-x\) 个红色小球已经与 \([1,i]\) 中的 \(cnt_{i,0}-x\) 个蓝色小球配对了,那么还没配对的蓝色小球数量一定满足 \(y=cnt_{i,1}-(cnt_{i,0}-x)\)。时间复杂度降至 \(O(n^4)\)。像这种延后决策的计数题后面会说。

然后是不太正常的连续段 DP。对于 \((i,p_i)\) 有关的问题,可以尝试连边 \(i \to p_i\)。那么会得到若干个置换环,每个置换环的价值为边的价值和。定义状态函数 \(f_{i,j,k}\) 表示插入 \([1,i]\) 的点后,形成了 \(j\) 个未合并的置换环与若干个已合并的置换环,且价值为 \(k\) 的方案数。那么从小到大加 \(i\),有:

  1. \(i\) 是一个新的环上某点。因为后面的都比 \(i\) 大,所以 \(f_{i,j+1,s-2i}=f_{i-1,j,s}\)
  2. \(i\) 是一个新的环上某点,且该环是一元环。\(f_{i,j,s}=f_{i-1,j,s}\)
  3. \(i\) 加在某个未合并的置换环两边。\(f_{i,j,s}=2 \times j \times f_{i-1,j,s}\)
  4. \(i\) 加在某个未合并的置换环两边,且发生两个置换环的连接。\(f_{i,j-1,s+2i}=2\times C_{j}^2 \times f_{i-1,j,s}\)
  5. \(i\) 加在某个未合并的置换环两边,且该置换环合并。\(f_{i,j-1,s+2i}=j \times f_{i-1,j,s}\)

最后答案为 \(f_{n,0,k}\)。时间复杂度 \(O(n^4)\)

P10547 [THUPC 2024 决赛] 排列游戏

和上面那题一模一样,只是 \(k=2m\)。很显然,\(O(n^4)\) 不够优秀。

根据摩天大楼的 trick,\(|i-j|\) 可以转化为 \(\sum\limits_{k=i+1}^{j} d_k\),其中 \(d_i=i-(i-1)\),即差分数组。那么只需要在每个 \(i\) 的时候额外加上 \(2j\) 就行了。时间复杂度变成 \(O(n^2m)\)。仍然不够优秀。进一步地,发现如果最后有 \(x\) 个置换环,那么价值和是 \(O(x^2)\) 级别的(构造 \((1),(2),(3),(4),\dots\))。所以置换环数量 \(O(\sqrt{m})\) 级别。那么时间复杂度降至 \(O(nm\sqrt{m})\)

延后决策

通常是一些信息对于当前局面不产生影响,但是会对之后决策形成的局面产生影响。这个时候利用技巧记录这些可能产生影响的信息就是延后决策了。

AT_abc134_f [ABC134F] Permutation Oddness

注意到 \(|i-p_i|=\max(i,p_i)-\min(i,p_i)\)。那么将 \(i=1\dots n\) 看成红色小球,\(p_i=1\dots n\) 看成蓝色小球。并且将它们按照值从小到大排序。则问题就相当于求:红蓝小球配对,配对价值为排在后面的小球的值减去排在前面的小球的值,求有多少种配对方式,使得这 \(n\) 个红蓝小球对的价值和为 \(k\)

定义状态函数 \(f_{i,x,y,s}\) 表示考虑完前 \(i\) 个球,有 \(x\) 个红色小球和 \(i\) 后面的蓝色小球配对,有 \(y\) 个蓝色小球和 \(i\) 后面的红色小球配对,且当前价值和为 \(s\) 的方案数。

  1. 红色小球。
    1. 匹配之前的蓝色小球。\(f_{i,x,y-1,s+v_i}=f_{i-1,x,y,s}\)
    2. 匹配之后的蓝色小球。\(f_{i,x+1,y,s-v_i}=f_{i-1,x,y,s}\)
  2. 蓝色小球。
    1. 匹配之前的红色小球。\(f_{i,x-1,y,s+v_i}=f_{i-1,x,y,s}\)
    2. 匹配之后的红色小球。\(f_{i,x,y+1,s-v_i}=f_{i-1,x,y,s}\)

这样做的时间复杂度 \(O(n^5)\)。已经可以过了。但是像这种配对问题通常有个简单的优化:记 \(cnt_{i,0/1}\) 表示前 \(i\) 个数中,红、蓝小球的数量。那么枚举 \(x\) 就能知道有 \(cnt_{i,0}-x\) 个红色小球已经与 \([1,i]\) 中的 \(cnt_{i,0}-x\) 个蓝色小球配对了,那么还没配对的蓝色小球数量一定满足 \(y=cnt_{i,1}-(cnt_{i,0}-x)\)。时间复杂度降至 \(O(n^4)\)

AT_arc207_a [ARC207A] Affinity for Artifacts

和上面的题一模一样,不说。

P8321 『JROI-4』沈阳大街 2

\(\prod \min(A_i,B_{p_i})\) 的和。经典小球题。

\(A,B\) 排序,然后配对即可。

P14364 [CSP-S 2025] 员工招聘

求排列 \(p\) 的数量,使得 \(f(p) \ge m\)。对于 \(f(p)\),有:

  1. 初始拒绝人数为 \(w=0\)
  2. 如果 \(s_i=0\),则拒绝的人数 \(w+1\)
  3. 如果 \(s_i=1\),且 \(c_i \le w\),则拒绝的人数 \(w+1\)
  4. 如果 \(s_i=1\),且 \(c_i >w\),则拒绝的人数不变。

\(f(p)\) 即为 \(n-w\)

像这种题,发现随着天数增加,拒绝人数不降,并且需要的 \(c\) 也不降。那么就可以尝试按照天数往后 DP。

进一步地,对于第 \(i\) 天的情况分类讨论:

  1. \(s_i=0\)。无论 \(c_j\) 是多少都会拒绝。
  2. \(s_i=1\)。需要满足 \(c_j > w\) 才不会拒绝。

发现我们只关心 \(c_j\)\(w\) 的大小关系(\(s_i=0\) 可以看做 \(>,=,<\) 都有),而不关心具体值。那么尝试设计状态函数 \(f_{i,w,j}\) 表示前 \(i\) 天结束,拒绝人数为 \(w\),且 \([1,i]\) 中一共有 \(j\)\(>w\) 的人的方案数。这样设计的好处是?

  1. 能够通过枚举 \(w\) 解决拒绝人数的问题。
  2. 能够通过预先站位,延后决策解决后面不知道某个数能不能选的问题。

考虑转移:

  1. \(s_i=0\)
    1. 这一天 \(c \le w\)。因为已知之前选择了 \(j\)\(>w\) 的人,所以能选的人数一定为 \(\sum\limits_{i=1}^{n}[c_i \le w]-(i-1-j)\)。维护 \(s_i=\sum\limits_{j=1}^{n}[c_j \le i]\)。枚举 \([1,i-1]\) 中有多少个选了 \(c > w\) 的位置恰好是 \(w+1\),那么有:\(f_{i,w+1,j-x}=f_{i-1,w,j}\times (s_w-(i-1-j))\times C_{cnt_{w+1}}^{x} \times C_{j}^{x} \times x!\)
    2. 这一天的 \(c=w+1\)。同理有 \(f_{i,w+1,j-x}=f_{i-1,w,j}\times C_{cnt_{w+1}}^{x+1} \times C_{j}^{x} \times (x+1)!\)
    3. 这一天的 \(c>w+1\)。延后决策了,先不管选了什么。\(f_{i,w+1,j-x+1}=f_{i-1,w,j}\times C_{cnt_{w+1}}^{x} \times C_{j}^{x} \times x!\)
  2. \(s_i=1\)
    1. 这一天的 \(c \le w\)。拒绝人数会增加,\(f_{i,w+1,j-x}=f_{i-1,w,j}\times (s_{w}-(i-1-j))\times C_{cnt_{w+1}}^x \times C_{j}^{x} \times x!\)
    2. 这一天的 \(c>w\)。拒绝人数不变,\(f_{i,w,j+1}=f_{i-1,w,j}\)

对于答案。枚举最后一天结束时的 \(w\),那么有答案为:\(\sum\limits_{w=0}^{n}f_{n,w,n-s_w}\times (n-s_w)! [n-w \ge m]\)

时间复杂度 \(O(n^4)\)。发现 \(x\) 的上界是 \(cnt_{w+1}\),那么枚举 \(i\) 时间复杂度 \(O(n)\),枚举 \(j\) 时间复杂度 \(O(n)\),枚举 \(w\) 时间复杂度 \(O(n)\),枚举 \(x\) 时间复杂度 \(O(cnt_{w+1})\)。后面两个总的时间复杂度 \(O(\sum\limits_{w=0}^{n}cnt_w)\),也就是 \(O(n)\) 的。那么这样转移就是对的。

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

P14465 霞む夏の灯

\(c_{\min(|i-p_i|,m)}\) 和一位。

套路地,构造 \(112233\dots nn\)。点 \(i\) 有颜色,红或蓝。红点表示原有的 \(i\),蓝点表示 \(p\)

首先如果这一位确定了,那么删掉 \(i,p_i\)。则现在问题变成:红蓝匹配,价值为 \(c_{\min(\max(u,v)-\min(u,v),m)}\)。求价值乘积的和。

因为 \(m\le 6\),也就是说我们只需要在意和 \(i\) 距离 \(<6\) 的点的状态与 \(\ge 6\) 的点被选择的数量。定义状态函数 \(f_{i,j,k,s}\) 表示前 \(i\) 个数,有 \(j\) 个红球匹配后面,\(k\) 个蓝球匹配后面与 \(\ge i+6\) 的位置匹配,\(i\) 前面 \(m\) 个数的状态为 \(s\) 的方案数。考虑加入 \(i\)

  1. 是红球。
    1. 匹配之前的蓝球。
      1. 匹配一个 \(i-j \le m\) 的蓝球。那么记 \(s\)\(0\) 的为已经配对的,\(1\) 为没有配对的。记 \(s'\) 为去掉某个 \(s\) 中的蓝球 \(1\) 且加入一个 \(0\) 的状态,同时去掉 \(i-m-1\)。则:\(f_{i,j,k-1,s'}=f_{i-1,j,k,s}\times c_{dis}\)
      2. 匹配一个 \(i-j > m\) 的蓝球。\(s'\) 为去掉 \(i-m-1\),且加入一个 \(0\) 的状态。则 \(f_{i,j,k-1,s'}=f_{i-1,j,k,s}\times c_{m}\times Cnt\)。其中 \(Cnt\) 为不在 \(s\) 中的之前的蓝球数量。
    2. 匹配之后的蓝球。\(s’\) 为去掉 \(i-m-1\),且加入一个 \(1\) 的状态。则 \(f_{i,j+1,k,s'}=f_{i-1,j,k,s}\)
  2. 是蓝球。
    1. 匹配之前的红球。
      1. 匹配一个 \(i-j \le m\) 的红球。那么记 \(s\)\(0\) 的为已经配对的,\(1\) 为没有配对的。记 \(s'\) 为去掉某个 \(s\) 中的红球 \(1\) 且加入一个 \(0\) 的状态,同时去掉 \(i-m-1\)。则:\(f_{i,j-1,k,s'}=f_{i-1,j,k,s}\times c_{dis}\)
      2. 匹配一个 \(i-j > m\) 的红球。\(s'\) 为去掉 \(i-m-1\),且加入一个 \(0\) 的状态。则 \(f_{i,j-1,k,s'}=f_{i-1,j,k,s}\times c_{m} \times Cnt\)。其中 \(Cnt\) 为不在 \(s\) 中的之前的红球数量。
    2. 匹配之后的红球。\(s’\) 为去掉 \(i-m-1\),且加入一个 \(1\) 的状态。则 \(f_{i,j,k+1,s'}=f_{i-1,j,k,s}\)

答案为 \(f_{n,0,0,0}\times \delta\)。其中 \(\delta\) 为原已经确定的位置的贡献和。时间复杂度 \(O(n^32^mm)\)。好像已经可以过了。

照搬优化方式,记 \(cnt_{i,0/1}\) 表示前 \(i\) 个数,红、蓝小球的数量。那么 \(k=cnt_{i,1}-(cnt_{i,0}-j)\)。时间复杂度 \(O(n^2 2^mm)\)。哦,因为同为 \(i\) 的有两个小球,所以 \(m=2m_0\)

CF1608F MEX counting

点。

因为我们不在意 \(\operatorname{MEX}=k\) 时,\(>k\) 的那些数具体是什么,那么可以尝试延后决策。定义状态函数\(f_{i,j,k}\) 表示前 \(i\) 个数,\(\operatorname{MEX}([a_1,\dots,a_i])=j\),且 \(>j\) 的数有 \(k\) 个的方案数。那么考虑对 \(a_i\) 的值分类讨论:

  1. \(a_i <j\)。加入后对 \(\operatorname{MEX}\) 无影响,有:\(f_{i,j,k}=f_{i-1,j,k}\times j\)
  2. \(a_i=j\)。加入后会让 \(\operatorname{MEX}\) 增加,且 \(\operatorname{MEX}\) 会变成第一个没出现过的值。枚举这个值为 \(j'\),且 \([j+1,j'-1]\) 中的数量为 \(x\)。则:\(f_{i,j',k-x}=f_{i-1,j,k}\times C_{k}^x \times g_{j'-j-1,x}\)。其中 \(g_{i,j}\) 表示给 \(j\) 个数涂色,每个颜色可以涂 \(i\) 种颜色,且每种颜色至少涂一次的方案数。有:\(g_{i,j}=i(g_{i,j-1}+g_{i-1,j-1})\)
  3. \(a_i>j\)。加入后对 \(\operatorname{MEX}\) 无影响,有:\(f_{i,j,k}=f_{i-1,j,k}\)

要求对于每个 \(i\)\(f_{i,j,*}=0 [|j-b_i|>k]\)

答案就是 \(\sum\limits_{j=0}^{n+1}\sum\limits_{k=0}^{n}f_{n,j,k}\times (n-j)^k\)。时间复杂度 \(O(n^5)\)

考虑优化。因为对于每个 \(i\)\(f_{i,j,*}=0[|j-b_i|>k]\)。所以直接枚举 \(|j-b_i|\le k\) 的位置转移的时间复杂度就变成 \(O(n^3k^2)\)。发现瓶颈在于第 \(2\) 类转移,但是好像怎么也优化不了。

那么尝试从状态定义进行优化。对于延后决策的实质,是不管对当前局面不产生影响的位置的具体值。发现对于 \([1,i]\) 中两个数 \(A_{j},A_k\)。如果 \(A_j=A_k\),那么本质上后面那个数是不会对所有局面产生任何影响的。所以可以尝试定义状态函数 \(f_{i,j,k}\) 表示,前面 \(i\) 个数,\(\operatorname{MEX}([a_1,\dots,a_i])=j\),且 \([1,i]\) 中比 \(j\) 大的数有 \(k\) 种的方案数。对 \(a_i\) 的值分类讨论:

  1. \(a_i<j\)。加入后对 \(\operatorname{MEX}\) 不产生影响。\(f_{i,j,k}=j \times f_{i-1,j,k}\)
  2. \(a_i=j\)。加入后对 \(\operatorname{MEX}\) 产生影响。枚举现在的值 \(j'\)。因为第三维状态是记录不同的值的数量,所以有:\(f_{i,j',k-(j'-j-1)}=f_{i-1,j,k}\times A_{k}^{j'-j-1}\)
  3. \(a_i>j\)
    1. \(a_i\) 这个值在之前没出现过。\(f_{i,j,k+1}=f_{i-1,j,k}\)
    2. \(a_i\) 这个值在之前出现过了,那么 \(i\) 不会对任何局面产生影响,\(f_{i,j,k}=k\times f_{i-1,j,k}\)

最后答案就是 \(\sum\limits_{j=0}^{n+1}\sum\limits_{k=0}^{n}f_{n,j,k}\times A_{n-j}^k\)。根据上面的优化,只维护有用信息,时间复杂度 \(O(n^2k^2)\)。对于第 \(2\) 类转移:

\[f_{i,j',k-(j'-j-1)}=f_{i-1,j,k}\times A_{k}^{j'-j-1}\\ f_{i,j',k-(j'-j-1)}=f_{i-1,j,k}\times \frac{k!}{(k-(j'-j-1))!} \]

换一下,有:

\[f_{i,j,k}=\frac{1}{k!}\sum f_{i-1,j',k+(j-j'-1)}\times (k+(j-j'-1))! \]

发现 \(j'+(k+(j-j'-1))=k+j-1\)。维护 \(g_{i,x,y}=\sum f_{i-1,j,k}\times k![j+k=y\land j \le x]\)。那么 \(f_{i,j,k}=\frac{1}{k!}g_{i-1,j-1,(j+k)-1}\)

对于 \(g_{i,j,k}\),先把 \(f_{i,j,k}\times k!\) 加到 \(g_{i,j,j+k}\) 上,再搞个前缀和 \(g_{i,j,k}=g_{i,j,k}+g_{i,j-1,k}\) 就行了。时间复杂度 \(O(n^2k)\)

由此,延后决策不光能做排列,还能做一般。(其实 AT_arc207_a 就可以看出来)

卡常,注意常数优化。

P8863 「KDOI-03」构造数组

直观感受,\(i\) 变成 \(b_i\) 需要 \(b_i\) 次操作,那么可以看做小球匹配问题。

注意到 \(\sum b_i \le 3\times 10^4\)。对于每个 \(i\),建立 \(b_i\) 个颜色为 \(i\) 的小球,那么问题变成:每次可以选择两个颜色不同的小球匹配,求不同匹配顺序的方案数。

直接做会算重,因为 \((x,y),(x,y)\) 在交换后等价。考虑方案数为:\(\frac{(\sum\limits_{i=1}^{V}cnt_i)!}{\sum\limits_{i=1}^{V}cnt_i!}\)。我们直接维护的是分子,现在需要对每种情况维护分母。

那么考虑那小球去填空,而不是匹配。也就是说,维护到 \(i\) 时,有多少个位置已经成对了,有多少个位置有 \(1\) 个,有多少个位置是空的。那么如果存在两个位置 \((0,y),(0,y)\)。同时拿 \(x\) 去填,就不会有问题了,因为我们不在意这两个 \(x\) 填的顺序或时间。

定义状态函数 \(f_{i,j,k}\) 表示前 \(i\) 个数填完,有 \(j\) 个位置有 \(1\) 个,有 \(k\) 个空位的方案数。那么对于 \(i\):枚举 \(x\) 个与有一个的位置成对,\(y\) 个填空位。则:\(f_{i,j-x+y,k-y}=C_{j}^{x}\times C_{k}^{y}\times f_{i-1,j,k}\),因为 \(x+y=b_i\),所以:\(f_{i,j-x+b_i-x,k-b_i+x}=C_{j}^{x}\times C_{k}^{b_i-x}\times f_{i-1,j,k}\)。时间复杂度 \(O(\frac{(\sum b_i) ^3}{4})\)

依旧套路优化,$k= \frac{\sum b_i}{2}-j-\frac{(\sum\limits_{x<i}^{}b_x)-j}{2} $。时间复杂度 \(O(\frac{(\sum b_i)^2}{2})\)

笛卡尔树上 DP

也就是枚举最大值,以最大值作为断点将排列划分成两部分。如果这两部分之间不产生依赖关系,那么问题可以变成两个本质相同的子问题,再通过组合数合并。

P9084 [PA 2018] Skwarki

首先发现最后剩下的数一定是 \(n\)

把笛卡尔树建出来,模拟一下。发现本质是每次同时删去只有不超过一个儿子的点。简单地想,由于笛卡尔树上 \(\operatorname{LCA}(l,r)\)\([l,r]\) 的最大值,那么当 \(u\) 只有一个儿子时,它和它父亲一定相邻。而父亲又比它大,所以会被删。注意笛卡尔树删一次后不一定仍然是树,需要再合并。

因为树根最后被删,所以尝试枚举最大值的位置。那么这个时候序列 \([1,n]\) 就被分成了 \([1,x-1]\)\([x+1,n]\)。注意到存在左右边界的情况,那么定义状态函数 \(f_{i,j,0/1,0/1}\) 表示将 \(1\dots i\) 的排列删完,需要 \(j\) 次操作,且该排列的左边、右边是否是边界的方案数。注意到一个排列不可能同时包含左、右边界,所以可以去掉第二维(因为最后枚举 \(n\) 的位置时一定会把 \([1,n]\) 分成两半)。

考虑最后一次是怎样删的:

  1. 左儿子删空的操作次数与右儿子删空的操作次数相同,那么此时需要额外 \(1\) 的代价将根删除。
  2. 左儿子删空的操作次数与右儿子删空的操作次数不同,当次数小的那边被删完后,根一定会在下一步被删除。

那么有转移方程:

\[f_{i,j+1,0}=f_{x,j,0}\times f_{i-x-1,j,0}\times \frac{(i-1)!}{(x)!(i-x-1)!}\\ f_{i,\max(j1,j2),0}=f_{x,j1,0}\times f_{i-x-1,j2,0}\times \frac{(i-1)!}{(x)!(i-x-1)!}[j1 \ne j2]\\ f_{i,\max(j1,j2+1),1}=f_{x,j1,1}\times f_{i-x-1,j2,0}\times \frac{(i-1)!}{(x)!(i-x-1)!} \\ \]

对于有边界的情况,如果 \(j1 \ne j2\),那么在 \(j1 < j2\) 的时候根会先变成端点,所以需要等到另一个儿子删完后再删除。

对于答案,有:\(\sum\limits_{i=2}^{n-1}f_{i-1,x,1}\times f_{n-i,y,1}\times \frac{(n-1)!}{(i-1)!(n-i-1)!}[\max(x,y)=k]+2\times f_{n-1,k,1}\)

发现每次至少删掉 \(\frac{n}{2}\) 个点,所以第二维是 \(O(\log n)\) 级别的。那么时间复杂度 \(O(n^2\log^2 n)\)

CF1580B Mathematics Curriculum

笛卡尔树上两点 \(\operatorname{LCA}\) 为区间最值。

那么 \(x\) 是好的当且仅当 \(dep_x=m\)。问题转化为:求排列 \(p\) 的数量,满足该排列对应的笛卡尔树中恰好有 \(k\) 个深度为 \(m\) 的点。

定义状态函数 \(f_{i,j,k}\) 表示大小为 \(i\) 的笛卡尔树中,深度为 \(j\) 的点有 \(k\) 个的方案数。那么将 \(i\) 插入排列,有:

  1. \(f_{i,1,1}=x!\times (i-x-1)!\times \frac{(i-1)!}{(x)!(i-x-1)!}\)
  2. \(f_{i,j+1,k1+k2}=f_{x,j,k1}\times f_{i-x-1,j,k2}\times \frac{(i-1)!}{(x)!(i-x-1)!}\)

答案为 \(f_{n,m,k}\)。时间复杂度 \(O(n^5)\),考虑优化。

直接卷可以做到 \(O(n^4\log n)\)。但是发现如果深度为 \(x\) 的点的数量不超过节点数的一半,卡一下好像就能过。

\(f_{x,j,k1}=0\) 时不转移就行了,稳定 700ms 内。

贡献提前计算

CF1437F Emotional Fishermen

求排列数量,要求:对于任意 \(i=1\dots n\),记 \(mx_i=\max\limits_{j=1}^{i}a_{p_j}\),则 \(a_{p_i}\ge 2mx_{i-1} \lor 2a_{p_i} \le mx_{i-1}\)

发现 \(mx_i \ge mx_{i-1}\),且在 \(a_{p_i}\ge 2mx_{i-1}\)\(mx_i=a_{p_i}\),在 \(2a_{p_i} \le mx_{i-1}\)\(mx_i =mx_{i-1}\)

如果已知排列 \(p\),那么可以将序列划分成若干段,每段都满足:

  1. \(a_{p_{l_i}}\ge 2a_{p_{l_i-1}}\)
  2. \(2\max\limits_{j=l_i+1}^{r_i}a_{p_j} \le a_{p_{l_i}}\)

也就是说,我们对前缀 \(\max\) 分段。

枚举前缀 \(\max\)\(a_i\)。定义状态函数 \(f_{i,j}\) 表示前缀 \(\max\)\(a_i\),且 \(2a_k \le a_i\)\(k\) 中有 \(j\) 个数没选择的方案数。枚举上一个前缀 \(\max\),那么有 \(cnt_i-cnt_{lst}+j-1\) 个数。那么:\(f_{i,cnt_i-cnt_{lst}+j-1-k}=f_{lst,j}\times A_{cnt_i-cnt_{lst}+j-1}^{k}\)

这里发现贡献延后不太好优化,因为时间复杂度稳定 \(O(n^4)\)

观察转移,发现当 \(a_i \ge 2a_{lst}\) 时,任意 \(2a_k \le a_{lst}\) 一定有 \(2a_k \le a_i\),也就是说,\(k\) 这个下标只要不是前缀 \(\max\),就一定可以放在第一个 \(2a_k \le a_i\) 后面的值作为前缀 \(\max\) 的段中。考虑贡献提前计算,那么有:\(f_i=\sum f_{lst}\times A_{n-1-cnt_{lst}-1}^{cnt_i-cnt_{lst}-1}\)。时间复杂度 \(O(n^2)\)

可以简单优化到 \(O(n)\)

根据排列中元素的相对顺序插入值

其实上面有一些题也是这个思路。下面的题就纯暴力了。

AT_abc282_g [ABC282G] Similar Permutation

求排列 \(p1,p2\) 的数量,使得 \(p1_i,p2_i\)\(p1_{i+1},p2_{i+1}\) 偏序情况相同的数量恰好为 \(k\)。因为我们不在意每个位置具体是什么数,类似于 AT_dp_t,尝试通过插入的方式维护。具体地,对于 \([1,i-1]\) 的排列和 \([1,i]\) 的排列,如果 \(p_i=j\),那么在 \([1,i-1]\) 的排列中的体现是将所有 \(p_k \ge j\) 的数增加 \(1\),从而保证之前的排列中不存在 \(j\) 这个值。例如:

\[p=\{1,2,4,8,3,6,5,7\}\\ p'=\{1,2,4,8(-1),3,6,5\} \]

可以保证,这样做对于每个 \([1,i]\) 的排列都有一个一一对应的 \([1,i-1]\) 的排列。也可以想象成将 \(p_n\) 删掉后,比它大的都应该减 \(1\) 来使得值域在 \([1,i-1]\) 且两两不同。

定义状态函数 \(f_{i,x,a,b}\) 表示前 \(i\) 个数,匹配的和为 \(x\),且 \(p1_i=a,p2_i=b\) 的方案数。那么有:

\[f_{i,x,a,b}=\sum\limits_{a' \ge a}^{}\sum\limits_{b'<b}^{}f_{i-1,x,a',b'}+\sum\limits_{a'<a}^{}\sum\limits_{b'\ge b}^{}f_{i-1,x,a',b'}\\ f_{i,x+1,a,b}=\sum\limits_{a'\ge a}^{}\sum\limits_{b'\ge b}^{}f_{i-1,x,a',b'}+\sum\limits_{a'<a}^{}\sum\limits_{b'<b}^{}f_{i-1,x,a',b'} \]

前缀和优化做到 \(O(n^4)\)

主观感受,这种按照相对顺序插入的做法不需要考虑排列是否会出现相同元素,通常可以在邻项产生偏序关系时使用。一般比连续段 DP 更好写。需要支持后缀或前缀整体加时无影响,即两个数的关系不随真实值变化而变化,只依赖相对大小。

AT_agc043_d [AGC043D] Merge Triplets

对于排列中连续 \(4\) 个数 \(p_{l},p_{l+1},p_{l+2},p_{l+3}\)。若 \(p_l>p_{l+1}>p_{l+2}>p_{l+3}\),显然不合法。因为只能将 \(3\) 个数分在一组,而无论怎么分都会有一个比 \(p_l\) 小。又因为连续,所以一定是一个栈或多个栈的栈顶。那么一定对。

则现在我们按照前缀 \(\max\) 划分,就可以得到若干个长度不大于 \(3\) 的段。需要将一些 \(1\) 的段和 \(2\) 的段合并,凑成刚好 \(n\) 个长度为 \(3\) 的段。显然,不能两个长度为 \(2\) 的段合并。则当长度为 \(1\) 的段的数量不小于长度为 \(2\) 的段的数量时,将 \(2\) 消耗完后一定能构造合法;且不满足时一定会至少剩下两个长度为 \(2\) 的段,一定不能构造合法。

那么一个排列合法,当且仅当:按照前缀 \(\max\) 划分后,所有段的长度 \(\le 3\),且长度为 \(1\) 的段的数量不小于长度为 \(2\) 的段的数量。

尝试按照相对大小确定排列。因为只在意 \(1\) 的数量和 \(2\) 的数量的大小关系,尝试定义状态函数 \(f_{i,j}\) 表示确定了 \(p_1\dots p_i\) 的相对大小,且 \(1\) 的数量减 \(2\) 的数量为 \(j\) 的方案数。那么:

  1. 加一个长度为 \(1\) 的段。那么 \(i+1\) 的相对大小一定是 \(i+1\)\(f_{i+1,j+1}=f_{i,j}\)
  2. 加一个长度为 \(2\) 的段。在 \(i+1\) 是最大的情况下,\(i+2\) 的大小不能大于 \(i+1\) 的值。\(f_{i+2,j-1}=(j+1)\times f_{i,j}\)
  3. 加一个长度为 \(3\) 的段。同上,有 \(f_{i+3,j}=(j+2)\times (j-1)\times f_{i,j}\)

最后答案就是 \(\sum\limits_{j\ge 0}^{}f_{n,j}\)。时间复杂度 \(O(n^2)\)

其它

CF1806D DSU Master

考虑 \((i,i+1,a_i)\) 在什么条件下会对答案贡献 \(1\)

  1. 如果 \(a_i=0\)。那么 \(find(i+1)\) 会连向 \(find(i)\)。此时只有在 \(find(i)=1\) 时才会有贡献,也就是说需要满足 \(\max\limits_{j=1}^{i-1}tim_j < tim_i\)\(find(i)=1\)
  2. 如果 \(a_i=1\)。那么 \(find(i)\) 会连向 \(find(i+1)\)。此时不可能产生贡献。

对于 \(\max\limits_{j=1}^{i-1}tim_j < tim_i\),方案数为 \(\frac{k!}{i-1}\)。对于 \(find(i)=1\),发现当 \(a_{i-1}=0\) 时,\(p(i)=p(i-1)\);当 \(a_{i-1}=1\) 时,\(p(i)=(1-\frac{1}{i-1})p(i-1)\)。因为 \(a_{i-1}\)\(1\) 的时候,一定要前面 \(tim\) 的最大值不大于 \(i-1\)\(tim\)。时间复杂度 \(O(n)\)

好像和排列计数没关系。

P4678 [FJWC2018] 全排列

如果已知 \(P_1,P_2\),就是求有多少个区间 \([l,r]\),满足 \(P_{1,l}\dots P_{1,r}\) 的逆序对数量不超过 \(E\),且 \(P_{1,i}\)\(P_{2,i}\) 的相对大小一样。直观地,就是离散化后相同。

那么根据离散化相同的限制,就可以得到:\((P_{1,i},P_{1,j})\)\((P_{2,i},P_{2,j})\) 偏序情况相同。

其实好像没必要,既然离散化了,不妨记 \(A=[P'_{1,l}\dots P'_{1,r}]\)。则 \(A\) 一定是 \(1\dots r-l+1\) 的排列。那么该区间会对所有离散化后为 \(A\)\((P_1,P_2)\) 产生贡献。方案数为:\((C_{n}^{r-l+1}\times (n-(r-l+1))!)^2\)

那么就很简单了,维护 \(f_i\) 表示所有 \(1\dots i\) 的排列中,逆序对数量不超过 \(E\) 的数量。则答案等于:\(\sum\limits_{i=1}^{n}f_i \times (C_{n}^{i}\times (n-i)!)^2\times (n-i+1)\)。定义状态函数 \(f_{i,j}\)\(1\dots i\) 的排列中,逆序对数量为 \(j\) 的方案数。从小到大加入 \(i\),因为 \([1,i-1]\) 都比 \(i\) 小,所以如果 \(i\) 排在位置 \(j\),则会对逆序对数量产生 \((i-j)\) 的贡献,有:\(f_{i,j}=\sum\limits_{x=0}^{i-1}f_{i-1,j-x}\)。时间复杂度 \(O(nE)\)

P2606 [ZJOI2010] 排列计数

\(i\) 和 $\lfloor i/2 \rfloor $ 连边。显然是棵二叉树,需要满足 \(u\)\(u\) 子树内所有点小。维护 \(f_{u}\) 表示 \(u\) 为根子树内点的相对大小满足条件的方案数。那么合并左右子树可以看做可重集排列的合并,因为各个子树相对顺序一定了。则:\(f_{u}=f_{ls_u}\times f_{rs_u}\times \frac{(siz_u-1)!}{(siz_{ls_u})!(siz_{rs_r})!}\)。时间复杂度 \(O(n)\)

注意 \(m\) 可能小于 \(n\)

AT_agc054_b [AGC054B] Greedy Division

困难。

如果第一个人选择得到橘子编号的顺序为 \(p_{1,1}\dots p_{1,m}\),第二个人选择得到的橘子编号的顺序为 \(p_{2,1}\dots p_{2,n-m}\)

发现,在已知 \(p_1,p_2\) 的情况下,\(p\) 是唯一的。有:

  1. 如果 \(sA \le sB\),那么只能在 \(p_i\)\(p_{1,*}\) 中的一个数,且一定是第一个没放的。
  2. 如果 \(sA >sB\),同理只能放唯一的一个数。
  3. 因为最初 \(sA=sB\),所以 \(p_1\) 也是确定的。

那么问题变成,维护集合 \(s\) 的数量,使得 \(\sum\limits_{i\in s}^{} w_i=\sum\limits_{i\notin s}^{} w_i\)。背包即可,时间复杂度 \(O(n^2V)\)

posted @ 2025-11-07 20:02  harmis_yz  阅读(351)  评论(7)    收藏  举报