排列有关 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})\)。

Jyu

【HT-098-Rainbow】核桃彩虹周赛 T4。

题面

题目描述

玖有一个 \(0 \sim n-1\) 的排列 \(p_1\dots p_n\)。也就是说,\(0\sim n-1\) 均在 \(p_1\dots p_n\) 中出现了恰好一次。

现在对于 \(i=1,2,\dots ,n\),妻求出了 \(f_{i}=\operatorname{MEX}(\{p_1,p_2,\dots,p_i\})\),瑶求出了 \(g_i=\operatorname{MEX}(\{p_i,p_{i+1},\dots,p_n\})\)。

珥根据 \(f_{1\dots n}\) 和 \(g_{1\dots n}\) 得到了 \(r(p)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[f_i < g_j]\)。其中 \(r(p)\) 可以看做一个关于排列 \(p\) 的函数。

如果 \(r(p)=k\),harmis 就会开心。fzitb 想知道,有多少排列 \(p\) 可以让 harmis 开心。排列 \(p\) 的数量对 \(m\) 取模。

注:\(\operatorname{MEX}(\{S\})\) 为最小的不属于 \(S\) 的自然数。

输入格式

一行三个整数 \(n,k,m\)。

输出格式

一行一个整数,表示满足条件的排列数量。

输入输出样例 #1

输入 #1

4 7 100000007

输出 #1

3

输入输出样例 #2

输入 #2

14 54 100000007

输出 #2

68494589

输入输出样例 #3

输入 #3

70 80 123456789

输出 #3

13510548

说明/提示

【数据范围】

本题采用捆绑测试。

  • Subtask 1(10 pts):\(1 \le n \le 10\)。
  • Subtask 2(10 pts):\(1 \le n \le 16\)。
  • Subtask 3(10 pts):\(1 \le n \le 25\)。
  • Subtask 4(5 pts):\(0 \le k \le n+1\)。
  • Subtask 5(20 pts):\(1 \le n \le 50\)。
  • Subtask 6(10 pts):\(0 \le k \le 200\)。
  • Subtask 7(35 pts):无特殊限制。

对于所有数据,保证 \(1 \le n \le 100,0 \le k \le 500,10^8 \le m \le 10^9\)。

注意常数。

记 \(pos_i\) 为 \(i\) 在排列 \(p\) 中的位置,即 \(p_{pos_i}=i\)。

当 \(i<j\) 时,显然 \(\min(f_i,g_j)=0\)。此时贡献为 \(\frac{pos_0\times (pos_0-1)}{2}\)。

当 \(i\ge j\) 时,发现 \(\min(f_i,g_j)=\operatorname{MEX}(\{p_i,p_{i+1},\dots,p_j\})\)。因为 \(\operatorname{MEX}(\{p_i,p_{i+1},\dots,p_j\})\) 不在 \([i,j]\) 左边就一定在 \([i,j]\) 右边。那么相当于维护区间 \([l,r]\) 的数量,满足 \(pos_{\operatorname{MEX}(\{p_l,p_{l+1},\dots,p_r\})} > r\)。

有贡献和为:\(\frac{pos_0\times (pos_0-1)}{2}+\frac{pos_0\times (pos_0-1)}{2}+\sum\limits_{i=1}^{n-1}(\min\limits_{j=0}^{i-1}pos_j)\times \max(0,pos_i-\max\limits_{j=0}^{i-1}pos_j)\)。显然 \(pos\) 和 \(p\) 是一一对应的,那么可以把 \(pos\) 看成一个 \(0\sim n-1\) 的排列。问题变成:求 \(1 \sim n\) 的排列 \(p\) 的数量,使得 \(p_1\times (p_1-1)+\sum\limits_{i=2}^{n}(\min\limits_{j=1}^{i-1}p_j)\times \max(0,p_i-\max\limits_{j=1}^{i-1}p_j)=k\)。

发现我们只关心 \([1,i-1]\) 中的最小值,最大值。考虑定义状态函数 \(f_{i,l,r,x}\) 表示 \([1,i]\) 的位置确定后,最小值为 \(l\),最大值为 \(r\),且上式的值为 \(x\) 的方案数。特殊转移 \(i=1\),对于 \(i \in [2,n]\) 有:

  1. \(l \le p_i \le r\)。此时对 \(l,r\) 无影响。\(f_{i,l,r,x}\leftarrow (r-l-i+2)\times f_{i-1,l,r,x}\)。
  2. \(p_i <l\)。此时 \(l \to p_i\)。\(f_{i,l',r,x}\leftarrow f_{i-1,l,r,x}[l > l']\)。
  3. \(p_i>r\)。此时 \(r\to p_i\)。\(f_{i,l,r',k+l\times (r'-r)}\leftarrow f_{i-1,l,r,x}[r<r']\)。

时间复杂度 \(O(n^4 k)\)。简单前缀和或后缀和优化做到 \(O(n^3k)\)。

发现 \(f_{i,l,r,*}\) 在 \(r-l+1 <i\) 时一定为 \(0\),此时只转移 \(r-l+1 \ge i\) 的状态复杂度降至原来的 \(\frac{1}{6}\)。足够了。

其实发现 \(x\) 这一维关于 \(l,r\) 也有限制。如果上面的过不了可以尝试从这一维优化。

笛卡尔树上 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)\)。

P9823 [ICPC 2020 Shanghai R] The Journey of Geor Autumn

考虑最小值放哪里。记 \(pos\) 为 \(1\) 的位置,那么 \(pos \in [1,k]\)。此时 \([pos+1,pos+k]\) 都是合法的。对于 \([pos+k+1,n]\) 这个序列,问题和 \([1,n]\) 是一致的,需要让序列 \([pos+1,n]\) 满足条件。定义状态函数 \(f_n\) 表示 \(n\) 个数的排列的方案数。

那么有:\(f_{n}=\sum\limits_{pos = 1}^{k}f_{n-pos}\times (pos-1)!\times \binom{n-1}{pos-1}\)。这里在 \(n \le k\) 时有 \(f_{n}=n!\)。表示我们将 \([1,pos]\) 和 \([pos+1,n]\) 融合。由于它们两个都是排列,所以可以看做相对大小关系将一个插入另一个(互不影响),且 \([1,pos]\) 这个排列只需要满足 \(p_{pos}=1\)。

化简一下转移,有:\(f_{n}=\sum\limits_{pos=1}^{k}f_{n-pos}\times \frac{(n-1)!}{(n-pos)!}\)。那么只需要维护 \(\sum\limits_{pos=1}^{k}\frac{f_{n-pos}}{(n-pos)!}=\sum\limits_{i=n-k}^{n-1}\frac{f_i}{i!}\) 了。前缀和优化可以做到 \(O(n)\)。瓶颈在于求逆元。

P14568 【MX-S12-T3】排列

如果 \(op_i \in \{0,1\}\)。考虑按照相对大小插入每个位置,那么每次看是插最前面还是最后面就行了。

如果 \(op_i \in \{0,1,2,3\}\)。如果 \(2\) 后面有个 \(0\) 或者 \(3\) 后面有个 \(1\) 答案显然是 \(0\)。否则所有 \(2\) 都在 \(0\) 后面,所有 \(3\) 都在 \(1\) 后面。考虑当前最后一个 \(2\) 的相对位置是 \(x\),最后一个 \(3\) 的位置是 \(y\)。那么再加入一个 \(2\),则一定需要在 \(x\) 前面且在 \(y\) 后面,记位置为 \(z\)。那么 \(x \gets z\)。不难发现,实际上我们只在意最后 \([y,x]\) 这个区间。

那么考虑定义状态函数 \(f_{i,j}\) 表示前 \(i\) 个数插完,这个区间的大小为 \(j\) 的方案数。

  1. \(op_i \in \{0,1\}\)。此时 \(op_i\) 对应的另一个限制(比如 \(0\) 对应 \(2\))一定还没出现,则区间在这个端点上没有限制。\(f_{i,j}\gets f_{i-1,j-1}\)。
  2. \(op_i \{2,3\}\)。枚举之后的区间大小 \(j\),则 \(f_{i,j}\gets \sum\limits_{k=j}^{i-1} f_{i-1,k}\)。

初始化 \(f_{0,0}=1\),答案为 \(\sum f_{n,i}\)。时间复杂度 \(O(n^2)\)。

P15301 [ROI 2012 Day 2] army 汗国军队

DP of DP 的题,在这里有更多的题。

考虑按照值从小到大插入序列,维护 \(f_i\) 表示当前位置 \(i\) 这个点如果是 \(\operatorname{LIS}\) 的末尾,此时 \(\operatorname{LIS}\) 的值是多少。

那么初始时 \(f_{i} = 0\)。将 \(x\) 这个值插入序列,若它插在位置 \(pos\)。那么有转移方程:\(f_{pos} = \max\limits_{j=0}^{pos-1}f_{j}+1\)。那么可以维护 \(g_{i} = \max\limits_{j=0}^{i}f_j\),则对于 \(i\in [pos,n]\) 有 \(g_{i}\gets \max(g_{i},g_{pos-1}+1)\)。

这样有个比较好的性质:\(g_i \in \{g_{i-1},g_{i-1}+1\}\)。那么再搞个差分数组就可以用一个二进制数维护 \(g\) 数组了。

因为题目要求 \(k\) 个数是某个 \(LIS\),考虑定义 \(dp_{s,lst,t}\) 表示加入完 \(1\sim \operatorname{popcount}(s)\) 这些值,最后一个属于题目给定的那 \(k\) 个数的值的位置在 \(lst\),且 \(g\) 数组的差分是 \(t\) 的方案数。

考虑转移,枚举 \(s,t\)。这个的时间复杂度是 \(O(3^n)\) 的,因为 \(t\) 中 \(1\) 的位置在 \(s\) 中也一定是 \(1\)(不可能这个位置还没有数但是 \(f\) 值比上一个大)。那么每个位置在 \(s,t\) 中的情况只会是 \(00,10,11\) 三种。再枚举当前这个值的位置 \(pos\),可以 \(O(n)\) 得到 \(s',t'\)。一共是 \(O(n^23^n)\) 的时间复杂度。然后再对每个 \(pos\) 枚举 \(lst\) 进行转移,时间复杂度依旧 \(O(n^23^n)\)。

那么总时间复杂度就是 \(O(n^23^n)\) 的,答案是 \(\sum dp_{U,lst,t}[\operatorname{popcount(t)}=k]\)。

但是时间复杂度有点不牛,考虑优化。注意到实际上这个 \(s\) 是没有任何作用的,因为我们任何时刻都只在意当前 \(1\sim i\) 这些值的相对位置。所以考虑定义状态函数 \(dp_{i,lst,t}\) 表示插入 \(1\sim i\) 这些值,最后一个属于题目给定的那 \(k\) 个数的值的相对位置是 \(lst\),\(g\) 数组的差分是 \(t\) 的方案数。

  1. 如果 \(i\) 不属于题目给定的 \(k\) 个数。枚举 \(t\) 和 \(i\) 插入的位置 \(pos\),表示 \(i\) 插在第 \(pos\) 个数之后。可以 \(O(n)\) 得到 \(t'\),时间复杂度 \(O(n^22^n)\)。再枚举 \(lst\):

    1. \(lst \le pos\)。\(dp_{i,lst,t'}\gets dp_{i-1,lst,t}\)。
    2. \(lst>pos\)。\(dp_{i,lst+1,t'}\gets dp_{i-1,lst,t}\)。

    时间复杂度依旧 \(O(n^22^n)\)。

  2. 如果 \(i\) 属于那 \(k\) 个数。还是枚举 \(t,pos\) 得到 \(t'\)。有转移:\(dp_{i,pos+1,t'}\gets dp_{i-1,lst,t}[lst \le pos]\)。

总时间复杂度 \(O(n^32^n)\),空间复杂度 \(O(n2^n)\)。

其实复杂度不是 \(O(n^22^n)\) 的。记:

\[s_n =\sum\limits_{i=1}^{n}2^ii^2,g_n = \sum\limits_{i=1}^{n}2^ii\\ \]

则:

\[s_{n+1} = \sum\limits_{i=1}^{n+1}2^ii^2\\ = 2^11^2 + \sum\limits_{i=1}^{n}2^{i+1}(i+1)^2\\ =2 + 2(\sum\limits_{i=1}^{n}2^i (i^2+2i+1))\\ =2s_n + 4\sum\limits_{i=1}^{n}2^ii + \sum\limits_{i=1}^{n + 1}2^i\\ =2s_n + 4g_n + 2^{n+2}-2\\ =s_n + 2^{n+1}(n+1)^2\\ \]

那么 \(s_n =2^{n+1}(n+1)^2 - 4g_n - 2^{n+2}+2\)。

\[g_{n+1}=\sum\limits_{i=1}^{n+1}2^ii\\ =2^11+\sum\limits_{i=1}^{n}2^{i+1}(i+1)\\ =2+2g_n + \sum\limits_{i=2}^{n+1}2^i\\ =2g_n+2^{n+2}-2\\ =g_n + 2^{n+1}(n+1) \]

那么 \(g_{n} = 2^{n+1}(n+1)-2^{n+2}+2\)。所以:

\[s_n \\=2^{n+1}(n+1)^2 - 4(2^{n+1}(n+1)-2^{n+2}+2)-2^{n+2}+2\\=2^{n+1}(n+1)^2 -2^{n+3}(n+1)+2^{n+4}-2^{3}-2^{n+2}+2 \]

也就是说,这种做法其实是 \(O(n^22^n)\) 的时间复杂度。

其它

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)\)。

AT_arc178_d [ARC178D] Delete Range Mex

如果合法,显然我们可以从大往小地删。因为先删一个小的后面可能就删不了大的了,明显不优。

记 \(i\) 的位置为 \(pos_i\)。那么删掉 \(x\) 的条件就是 \(pos_x > \max\limits_{i=0}^{x-1}pos_i \lor pos_x <\min\limits_{i=0}^{x-1}pos_i\)。那么我们可以 \(O(n)\) 判断 \(B\) 能否删成 \(A\)。

由于我们只在意前缀的最小 \(pos\),最大 \(pos\) 与 \(pos_x\) 的相对大小关系。定义状态函数 \(f_{i,l,r}\) 表示现在填完 \([0,i]\),\(pos\) 的最小值相对顺序在 \((A_{l},A_{l+1})\) 间,最大值在 \((A_{r-1},A_{r})\) 的方案数。这里填的点不在意 \(A\) 中的点。

  1. \(i\) 在 \(A\) 中出现过。不管。\(f_{i,l,r} = f_{i-1,l,r}\)。
  2. \(i\) 没在 \(A\) 中出现过。我们可以知道 \([0,i-1]\) 中在 \(A\) 里的最小,最大位置。记为 \(l_i,r_i\)。那么 \(i\) 的位置要么在 \(\min(l_i - 1,l)\) 左边,要么在 \(\max(r_i + 1,r)\) 右边。有:\(f_{i,l',r}=f_{i-1,l,r}[l' \le \min(l_i - 1,l)]\),\(f_{i,l,r'}=f_{i-1,l,r}[r' \ge \max(r_i + 1,r)]\)。可以前缀和优化。

CF1439D INOI Final Contests

不知道算啥,拆贡献吗。

最后有人的位置肯定是很多个区间。因为各自区间独立,所以只需要对每个区间都算一下再拼起来。

先不考虑计算贡献,只计算方案数。定义 \(f(n)\) 为 \(n\) 台电脑,\(n\) 个人坐满的方案数。对于最后一个人,设他的位置是 \(pos\),那么应该满足:

  1. \(b_n = L\),此时 \(a_n \le pos\)。
  2. \(b_n = R\),此时 \(a_n \ge pos\)。

共 \(n+1\) 种选择,然后就变成 \([1,pos-1]\) 和 \([pos+1,n]\) 两个子问题了。有:\(f(n) =(n+1)\sum\limits_{pos=1}^{n}f(pos-1)f(n-pos)\binom{(pos-1)+(n-pos)}{(pos-1)}\)。

简单的,既然我们枚举了每个人的 \(pos\),那么就可以维护每个人的贡献。即:

  1. \(b_n = L\),此时贡献为 \(pos - a_n\)。
  2. \(b_n = R\),此时贡献为 \(a_n - pos\)。

记 \(c(n,pos) = \sum\limits_{i=1}^{pos}(pos -i) + \sum\limits_{i=pos}^{n}(i-pos)\)。将贡献拆开,维护 \(f(n,0/1)\) 为 \(n\) 台电脑,\(n\) 个人坐满,且是否有一个人计算了贡献的方案数(乘上贡献和)。比如第 \(n\) 个人产生了贡献,就是:\(f(n,1)\gets \sum\limits_{pos=1}^{n}c(n,pos)f(pos-1,0)f(n-pos,0)\binom{(pos-1)+(n-pos)}{(pos-1)}\)。

最后将区间拼起来,定义 \(g(n,x,0/1)\) 为 \(n\) 台电脑,坐了 \(x\) 个人,且是否有一个人计算了贡献的方案数(乘上贡献和)。转移是简单的,枚举最后一个区间的长度再前缀和即可。最后答案为 \(g(n,m,1)\)。时间复杂度 \(O(n^3)\)。
最后答案就是 \(\sum f_{n-1,l,r}\)。时间复杂度 \(O(n^3)\)。

CF2154F2 Bombing (Hard Version)

考虑枚举 \(k\)。令 \(p_0 = 0,p_{n+1}=n+1\)。

将值 \([0,k]\) 看成黑色,\([k+1,n+1]\) 看成白色。对于相邻两个已知值的位置 \(i,j\)(\(i<j\)):

  1. \(p_i\) 是黑色,\(p_j\) 是黑色。因为值 \([0,k]\) 在排列上的位置是单增的,所以 \([i+1,j-1]\) 包含了 \([p_i+1,p_j-1]\) 所有值。方案数为 \(\binom{(j-1)-(i+1)+1}{(p_j-1)-(p_i+1)+1}\)。
  2. \(p_i\) 是白色,\(p_j\) 是白色。同样方案数为 \(\binom{(j-1)-(i+1)+1}{(p_j-1)-(p_i+1)+1}\)。
  3. \(p_i\) 是黑色,\(p_j\) 是白色。对于下标 \([0,i]\) 来说,因为 \(p_i\) 是里面黑色最大值,所以有 \(p_i+1\) 个黑色和 \((i+1)-(p_i+1)\) 个白色;对于下标 \([0,j]\) 来说,因为 \(p_j\) 是里面白色最大值,所以有 \(p_j-k\) 个白色,\((j+1)-(p_j-k)\) 个黑色。通过差分不难得到,\([i+1,j-1]\) 中有 \((p_j-k)-((i+1)-(p_i+1))-1\) 个白色,\(((j+1)-(p_j-k))-(p_i+1)\) 个黑色。方案数为 \(\binom{(j-1)-(i+1)+1}{((j+1)-(p_j-k))-(p_i+1)}\)。
  4. \(p_i\) 是白色,\(p_j\) 是黑色。对于下标 \([0,i]\) 来说,因为 \(p_i\) 是里面白色最大值,所以有 \(p_i-k\) 个白色和 \((i+1)-(p_i-k)\) 个黑色;对于下标 \([0,j]\) 来说,因为 \(p_j\) 是里面黑色最大值,所以有 \(p_j+1\) 个黑色,\((j+1)-(p_j+1)\) 个白色。通过差分不难得到,\([i+1,j-1]\) 中有 \(((j+1)-(p_j+1))-(p_i-k)\) 个白色,\((p_j+1)-((i+1)-(p_i-k))-1\) 个黑色。方案数为 \(\binom{(j-1)-(i+1)+1}{((j+1)-(p_j+1))-(p_i-k)}\)。

整合一下:

  1. \(p_i,p_j\) 同色。方案数为 \(\binom{j-i-1}{p_j-p_i-1}\)。
  2. \(p_i,p_j\) 异色。方案数为 \(\binom{j-i-1}{j-p_i-p_j+k}\)。

维护 \(f_k\) 为 \(k\) 固定时这些组合数的乘积。

如果 \(p_i,p_j\) 异色且合法,需要满足:

  1. 记 \(x=\min(p_i,p_j),y=\max(p_i,p_j)\)。则 \(\max(x,x+y-j) \le k <\min(y, x+y-i)\)。

发现 \(\min(y, x+y-i) - \max(x,x+y-j) \le j-i\)。那么暴力枚举 \(k\),并将 \(f_k\) 乘上 \(\binom{j-i-1}{j-p_i-p_j+k}\) 均摊就是 \(O(n)\) 的,还需要维护一个 \(g_k\) 表示 \(k\) 被多少个相邻项贡献了组合数(因为 \(\binom{j-i-1}{j-p_i-p_j+k}=0\) 的没有枚举)。

如果 \(p_i,p_j\) 同色且合法,需要满足:

  1. \(p_i<p_j\)。
  • \(p_j \le k\) 或 \(p_{i} > k\)。

维护前缀、后缀乘某个数即可。也是 \(O(n)\) 的。

那么整体时间复杂度 \(O(n)\)。同时如果 \(p = [1,n]\) 是合法的,需要将答案减去 \(n-2\)。

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