dp 做题记录 2

CF1679F Formalism for Formalism

考虑找到一类等价的方案的一个代表元来建立单射关系,具体的,在本题令字典序最小的序列来代表整个序列集合。

考虑怎么判定一个串是字典序极小的。

对于每个 \(a_i\),找到前面极长的一个后缀 \(a_{j \sim i-1}\) 使得 \(a_{k \in [j,i)}\) 可以与 \(a_i\) 交换,如果 \(\max_{k \in [j,i)}a_k \le a_i\),那么这个串就是极小的。

证明:如果不满足条件,那么把 \(a_i\) 换到那个比它大的数前面可以让字典序更小。如果想让 \(a_i\) 移到 \(j\) 前面,那么就必须把 \(a_j\) 往前移,反而字典序会变大。

观察到 \(|\Sigma| = 10\),考虑状压字符集,然后就可以 dp 了,记 \(f_{i,S}\) 代表考虑 \([1,i]\),下一位可以填的字符集合为 \(S\) 的方案数。

转移枚举 \(i \in S\),如果 \(0 \le j < i \wedge (i,j)\) 可交换,那么从 \(S\) 中移除,然后加入所有 \((i,j)\) 不能交换的 \(j\),这个容易 \(O(1)\) 转移。时间复杂度 \(O(n |\Sigma|2^{|\Sigma|})\)

CF1810G The Maximum Prefix

考虑如何判定 \(a\) 数组的最大前缀和为 \(x\),那么需要前缀和数组 \(s\) 满足 \(\max\limits_{i \in [0, n]}(s_i)=x\)

将这个条件改写为 \(\forall s_i \le x, \exists s_i = x\)

考虑对着这个判定条件 dp,记 \(f_{i,j,0/1}\) 代表考虑 \([1,i]\)\(x-s_i\) 的值为 \(j\),是否有满足过第二个条件(也可以 \(j\) 的答案扣掉 \(j-1\) 的答案),转移为 \(f_{i,j,k |[j=x]} = p_i f_{i-1,j+1,k}+(1-p_i)f_{i-1,j-1,k}[j>0]\)

时间复杂度 \(O(n^2)\),注记一下这个题的另一种思路是倒着维护前缀最大值,对于 \(i=n \to 1\) 依次 \(s = \max(s+a_i, 0)\)

CF924F Minimal Subset Difference

考虑怎么判定一个串是不是合法。记 \(g_{i}\) 代表是否存在划分方案使得差的绝对值 \(=i\),加入一个数 \(c\),那么有转移 \(g_{i} \to g_{i+c},g_{|i-c|}\)

观察到第二维的大小肯定不会超过 \(9 \times 9=81\),题解说可以开到 \(72\) 但是不会证。

猜想 \(g\) 的有效状态数不会很多,对 \(g\) 建立自动机,跑出来 \(g\)\(10^4\) 级别个节点,也就是说 \(g\) 的有效状态非常少。

然后就可以做 dp 套 dp 了,直接做数位 dp 即可,开一个 map 对 \(g_S\) 离散化,然后记 \(f_{i,S,k}\) 代表还剩下 \(i\) 位,当前状态为 \(S\),限制为 \(k\) 的方案数。

时间复杂度 \(O(K |\Sigma| \log K + (K|\Sigma| + T) |\Sigma| \log_{|\Sigma|} V)\),其中 \(K=12880,|\Sigma|=10\)

AGC061C First Come First Serve

为什么做过的题我还是不会 /ll。

如果两种方案,存在一个人选择了一个不同的端点,并且他们的排列顺序相同,则我们称这两个方案等价。

考虑什么时候会出现等价方案,如果一个人的区间 \([L_i,R_i]\) 里面不存在一个点被其他人选择,那么这个人取左右端点都是等价的。

所以我们考虑建立单射关系,让字典序尽可能小,对于所有这种不被限制的区间强制取左端点。

对于单射成立的证明:如果两种方案所有的不被限制的区间都取了左端点且等价,找到第一个人使得他选择的端点不同,必然会导致两种排列不同,矛盾。

接下来考虑钦定不合法区间的个数进行容斥,容斥系数为 \((-1)^c\)。具体来说,我们把容斥系数加入到 dp 状态,也就是 \(f_i = 2f_{i-1} - \sum_{j \in S_i} f_j\),考虑 \(S\) 是怎么构成的。对每一对 \((L_i,R_i)\),找到最大的 \(p\) 满足 \(R_p < L_i\),和最小的 \(q\) 满足 \(R_i < L_q\),那么 \([p,q]\) 的决策确定,也就是将 \(p-1\) 加入 \(S_q\)

因此就做完了,时间复杂度 \(O(n)\)

AGC056B Range Argmax

多个 \(p\) 可能对应到一个相同的 \(x\) 的数组上,考虑建立 \(x \to p\) 的单射。

考虑如下过程:对于 \(i=n \to 1\),依次插入 \(i\) 到能放置的最左位置。

确定了最大值之后,那么剩下没填的数肯定都比最大值小,也就是说所有包含了 \(i\) 的区间的限制都失效了,记 \(i\) 填在了 \(p\),问题变为 \([l,p)\)\((p,r]\) 两个相似的子问题。

考虑断点 \(p\) 对区间的限制,对左边区间需要满足存在区间使得最大值的放置位置 \(k,p\) 在同一个限制区间内,对右边无限制。

所以我们考虑区间 dp,考虑还需要记录当前最大值最左能放置的位置,所以设 \(f_{l,r,k}\) 代表考虑区间 \([l,r]\),最大值放置位置 \(\ge k\) 的方案数。

所以开一个辅助数组 \(g_{l,r,k}\) 代表被完全包含于 \([l,r]\) 且包含 \(k\) 的限制区间的左端点的最小值。

dp 转移是简单的:\(f_{l,r,k}=f_{l,r,k+1}+f_{l,k-1,g_{l,r,k}}\times f_{k+1,r,k+1}\)。时间复杂度 \(O(n^3)\)

P8194 [USACO22FEB] Phone Numbers P

观察到 \(i+1\) 最多和前面 \(3\) 个数一起匹配,因此可以考虑把前三位和前三位的匹配情况加入状态,记 \(f_{a,b,c,d,e,f,g}\) 代表 \(i-2\) 位是 \(a\)\(i-1\) 位是 \(b\),第 \(i\) 位是 \(c\)\([1,i-3]\) 是否完全匹配,\([1,i-2]\) 是否完全匹配,\([1,i-1]\) 是否完全匹配,\([1,i]\) 是否完全匹配。这样的 dp 状态数是 \(O(2^4 9^3 n)\) 的,显然不能通过。

我们观察到如果 \(d=0\),那么 \(a\) 的值其实不重要可以直接合并状态。同理如果 \(d=e=0\),那么 \(b\) 的值也可以直接合并。同理 \(c\)\(s_{i+1}\) 也可以进行类似合并。

继续观察到如果 \(a,b,c\) 不同时在一个正方形内,那么 \(a\) 的值就没有意义,类似地,如果 \(b,c\) 不在一个正方形内,\(b\) 的值也不重要,因此又可以进一步压缩。

这两步压缩完了之后状态缩减到了 \(150\) 个左右,做 dp 便可以卡卡常通过,时间复杂度 \(O(n |\Sigma| K)\),其中 \(K = 150\),代码总之就是非常难写。

QOJ 7766. [集训队互测 2023] 栞

网上的唯一一篇题解写的就是屎,还有一堆错误 /fn。

考虑 sub3 的特殊性质 \(q_i=i\) 怎么做:

发现对于一个前缀 \(p[1 \sim i]\),且值域上恰好对应 \(1 \sim i\)\(\max_{1 \le j \le i} p_j=i\),可以直接对 \(1 \sim i\) 排序会满足 \(q\)\(i\) 项的限制。而且如果有两个满足该条件的前缀 \(1 \sim i, 1 \sim j(i \le j)\),那么对 \([1,i]\) 排序,\((i,j]\) 也是一个 \((i,j]\) 值域上的排列,也对 \((i,j]\) 排序,也会得到排列 \(q\) 的前 \(j\) 项。

由于 \(k\) 越小,答案字典序单降。所以我们应该尽可能让段数更多。因此我们对极小的段的个数 dp。设 \(f_{i,j}\) 代表前 \(i\) 个数划分成了 \(j\) 个极小段的方案数。答案即为 \(\sum_{k \le i \le n} f_{n,i}\) 对于 \(j \ge 1\),枚举最后的一个极小段长度 \(k\),有转移:

\[f_{i,j} = \sum_{1 \le k \le i - j + 1} f_{k,1}f_{i-k,j-1} \]

考虑 \(f_{i,0}\) 怎么算,考虑对于一个 \(1 \sim i-1\) 的排列,插入 \(i\),找到第一个满足上面条件的前缀 \(j\),那么 \(j\) 前面必须插入一个 \(i\)。则有转移:

\[f_{i,0} = \sum_{1 \le j < i} f_{j,0}j(i-1-j)! \]

接下来考虑正确做法:我们记满足 \(q_{i-1}>q_i\) 的点为一个断点。

考虑 \(f_k(p)\) 是怎么生成的,在 \(i \in [1, n-k]\) 选出一个最小值,删除它,得到 \(q_1\),继续这个流程得到 \(q_{2,3...}\),直到选中 \(n-k\)。按照上面的分段思路,很容易可以得到,\(1 \sim i\) 可以划分为一段的条件是 \(\{q_1,q_2,...,q_i\} = \{p_1,p_2,...,p_i\}\)

我们记 \(q\) 的第一个断点为 \(t\),第二个断点为 \(t'\),那么有以下结论:

\(q\) 生成的 \(p\) 的形态如下:

\([1,t)\) 被划分成若干段,\([t,t')\) 整体成一段,并且如果 \(t'>t+1\),则有 \(\min_{t \le i \lt t'} p_i\) 位于 \(t'-1\)\(q_{t+1}>q_{t-1}\),然后 \([t',n]\) 每个数字单独成一段。

一个简要的证明:

\([t,t')\) 单独成段的意义在于,可能会刚好把最小值卡在最后一个并且 \(k\) 刚好要求最小值独立成段,例如 \(q=[1,3,2,4,5,7,6],k=4\),一种存在的 \(p=[3,1,5,4,2,7,6]\)。如果最小值不在 \([t,t')\) 的末尾,完全可以把最后一个数单独裂出去,答案更优。如果不满足 \(q_{t-1}<q_{t+1}\),把 \(q_t\) 或者 \(q_{t+1}\) 合并到前面,答案更优。

那么枚举 \(t'\),答案即为 \(\sum_{t'}f_{t-1,k-(n-t'+2)}(t-t'-1)!\),时间复杂度 \(O(n^3)\)

CF1762F Good Pairs

简单 dp 题,很容易观察到从 \(l\)\(r\) 的路径在权值上一定是单调的,下文只讨论单调递增的情况。

\(f_i\) 代表 \(i\) 往右走可达的位置的总个数,\(i\) 的决策应该是往右跳第一个 \(j\) 使得 \(a_i \le a_j \le a_{i}+k\),记 \(R_i=j\),那么得到转移 \(f_i = f_j + w(i,n,a_i+1,a_j)\)\(w(a,b,c,d)\) 代表区间 \([a,b]\) 有多少个位于 \([c,d]\) 的数。然后做完了,记得要特别算 \(a_i=a_j\) 的答案。时间复杂度 \(O(n \log n)\)

P8386 [PA 2021] Od deski do deski

考虑如何判定一个序列能不能被消去,记 \(f_i\) 代表前 \(i\) 个数能否被消除,那么显然有转移 \(f_i = \bigvee_j [a_i=a_j]f_{j-1}\)。观察到对于 \(f_i\) 来说,我们并不关心前面 \(f_j\) 的具体位置,我们只关心 \(\{a_j | f_{j-1}=1\}\) 的集合。

又考虑到问题是对判定计数,也就是说 \(\{a_j | f_{j-1}=1\}\) 其实我们是不关心的,我们只关心 \(|\{a_j | f_{j-1}=1\}|\),记这个为集合 \(S\),那么 dp 定义就出来了,定义 \(f_{i,j,0/1}\) 代表考虑 \([1,i]\),集合 \(S\) 大小为 \(j\)\(f_{i-1}\)\(0/1\) 的方案数。

那么直接转移即可,时间复杂度 \(O(n^2)\)

AGC064D Red and Blue Chips

先考虑怎么判断一个结果是否合法。

观察到 \(S_n\) 前面的一段极长的 R,一定会放到 \(T\) 串的一段前缀。

继续观察,更前面的一个 B 前的一段极长的 R,可以选择塞到前缀或者第一个 B 的后面。

一个 B 后面能赛的 R 的最大数量应该是 B 在 \(T\) 串对应的那个 B 后面的连续的 R 的数量,为了尽可能赛更多 R,我们从 \(S_n\) 考虑到 \(S_1\) 的过程中,应该优先把 B 去对应 \(T\) 串尽可能多的那一段,然后这样可以塞进去更多的 R。

这样,我们就把题目条件改写为了,给定 \(b_{1 \sim k}\),你需要求出满足下列条件 \(a_{1 \sim k}\) 的数量:

  • \(a_1 \ge b_1\)
  • \(\sum a_i = \sum b_i\)
  • \(a_{2 \sim k}\) 从大到小排序后,\(\sum_{j=1}^i a_j \ge \sum_{j=1}^i b_j\)

这个问题就是 CF1740F,这个是经典的,由于本题是有序的所以转移要乘上一个阶乘的逆,设 \(f_{i,j,k}\) 代表当前最小值为 \(i\),确定了 \(j\) 个数,所有数的和是 \(k\)

时间复杂度是 \(\sum_i \sum_j \sum_{k \le j/i}(n-j)/k = O(n^3)\)

CF354D Transferring Pyramid

首先考虑把所有格子往左边靠拢,每次修改一个斜三角形状物。

一个观察是这个三角形修改的边长是 \(O(\sqrt n)\) 级别的,否则就不如单点修改优秀。那么就可以进行 dp 了,因为三角形可以重叠,感觉一维的断点转移 dp 不是很能刻画,记 \(f_{i,j}\) 代表从右往左 dp,当前三角形的高度为 \(j\)。考虑转移 \(i + 1 \to i\),可以继续延申这个三角形,结束这个三角形或者这一列直接全部单点修改。

由于三角形可以重叠,所以可以 \(f_{i,0} \to f_{i,j}\),转移是简单的,时间复杂度 \(O(n \sqrt n)\)

CF1784D Wooden Spoon

如果一个人 \(i\) 拿到了勺子,那么肯定他在第一场已经输了,也就是存在序列 \(1=x_1<x_2<...<x_n=i\)。考虑从 \(1\)\(n\) 从上到下 dp。记 \(f_{i,j}\) 代表计算到第 \(i\) 层,\(x_i=j\) 的方案数,那么有转移:

\[f_{i,j} = 2 \times (2^{n-i})! \times \binom{2^{n}-j}{2^{n-i+1}-1}\binom{2^{n-i+1}-1}{2^{n-i}-1} \sum f_{i-1,k} \]

系数的解释是,\(2\) 是因为 \(j\) 可以在任意一棵子树内,\((2^{n-i})!\) 是因为另外一棵子树可以随意排列,后面两个组合数是先在 \((j,2^n]\) 中选择 \(2^{n-i+1}-1\) 个数放在这个子树内,然后再选 \(2^{n-i}-1\) 个数放在其中一个子树里面。

前缀和优化即可,时间复杂度 \(O(n2^n)\)

CF1765C Card Guessing

根据期望的线性性,把贡献拆成每一位猜对的概率,我们记 \(c = \min(k,i-1)\),枚举 \(c_1,c_2,c_3,c_4(c_1+c_2+c_3+c_4=c)\),记 \(m = \min(c_1,c_2,c_3,c_4)\),方案数就是:

\[\binom{c}{c_1,c_2,c_3,c_4}\binom{4n-c}{n-c_1,n-c_2,n-c_3,n-c_4}\dfrac{\binom{4n-c-1}{n-m-1}}{\binom{4n-c-1}{n-m}} \]

拆开后得到:

\[\dfrac{c!(4n-c-1)!(n-m)}{c_1!c_2!c_3!c_4!(n-c_1)!(n-c_2)!(n-c_3)!(n-c_4)!} \]

直接背包即可做到 \(O(n^3)\),进一步,从小到大枚举值域进行背包,在加入第一个物品时加入 \(m\) 的系数即可,注意转移过程中,如果加入 \(d\)\(i\),则需要乘上 \(\dfrac{1}{d!}\),最后乘上 \(4!=24\) 即可,时间复杂度 \(O(n^2)\)

CF1060F Shrinking Tree

考虑以 \(u\) 为根,此时如果合并 \((u,v)\) 并保留 \(u\),可以视作把 \(v\) 的所有子树挂到 \(u\) 身上。

不显然地得出 dp 状态,设 \(f_{u,i}\) 代表 \(u\) 字数内,最后缩的 \(i\) 对边满足缩完之后根不变的概率。\(u\) 的答案即为 \(\dfrac{f_{u,n-1}}{(n-1)!}\)

先考虑合并父亲与儿子边 \((u,v)\) 的过程,枚举这条边是在剩下 \(i\) 次合并的时候被缩掉,对于 \(f_{v,j}\) 的贡献,分类讨论:

  • \(i \le j\):那么则需要强制让这条边选择 \(u\),即 \(\frac{1}{2}f_{v,i-1} \to f_{u,i}\)
  • \(i > j\):那么这条边怎么选择都无所谓,即 \(f_{v,j} \to f_{u,i}\)

再考虑怎么合并两个地位相同的儿子,枚举 \(f_{v_1,i},f_{v_2,j}\),那么对于缩边序列的限制应该是,这 \(i+j\) 条边全部在 \(siz_{v_1}+siz_{v_2}-i-j-2\) 条边前面,那么系数应该是 \(\displaystyle\binom{i+j}{i}\binom{siz_{v_1}+siz_{v_2}-i-j-2}{siz_{v1}-i-1}\),这个显然就可以直接背包了。

直接做就是 \(O(n^4)\) 的,对 \(v \to u\) 的过程前缀和优化即可做到 \(O(n^3)\)

六校联考 20251105C. 物品采购(judge)

  • \(type=1:\)

手画不难发现,如果一个序列有 \(\le 2\) 个颜色段,那么它的贡献是 \(0\),因为任意一个子序列都会是子段。

否则贡献是 \(n-2\),因为可以任意漏选中间颜色段的一个元素,时间复杂度 \(O(n)\)

  • \(type=2:\)

直觉上告诉我们,序列应该形如 \(S_0,x,S_1,x,S_2\),我们可以选择 \(S_0+x\) 或者 \(x+S_2\)

这样应该是最优的,如果我们选 \(S_0,x\) 之后还选了 \(y\),那么完全可以 \(S_0:=S_0+x,y:=x\)

需要注意不能出现 \(S_0=S_2=\varnothing\),扫一遍即可,时间复杂度 \(O(n)\)

  • \(type=3:\)

考虑对 \(type=1\) 计数,首先容斥,总贡献为所有子序列的长度之和,设 \(n\) 的答案为 \(f_n\)

那么显然有递推式:\(f_n = 2f_{n-1} + 2^{n-1}\),求出来即可。

然后首先可以扣掉颜色段数为 \(1\) 的子序列,接下来考虑扣掉颜色段数为 \(2\) 的子序列。

不妨枚举第一个颜色段的末尾下标 \(p\),对于 \(p\) 前面的限制是选若干个等于 \(p\) 的,对 \(p\) 后面的限制是选若干个一样的。

因此维护 \(pre_{0/1,i},suf_{0/1,i}\) 代表前后缀的贡献和和方案数,记得最后要减去一个总方案数。

扫一遍前后缀即可,时间复杂度 \(O(n)\)

  • \(type=4:\)

前面的三个部分应该都是平凡的,首先可以 \(O(2^nn)\) 暴力,然后场上根据暴力想了一个 \(O(n^4) \sim O(n^5)\) 的做法。

大概是枚举前面两个相同的,后面两个相同的下标算贡献,没写出来也不保证正确。

我们重新审视 \(type=2\) 的限制,发现这个限制并不方便计数,我们对其做转化:

\(k\) 为满足前 \(k\) 个两两不同,后 \(k\) 个两两不同的最大值。那么每个序列的贡献为 \(n-k-[k=n-1]\)

\([k=n-1]\) 的意义就是首尾相同,且中间都不同的序列答案应该是 \(0\)

对于这个式子,\(\sum n=f_n\) 已经在上面计算过,\([k=n-1]\) 可以枚举 \(p,q(p<q,a_p=a_q)\),设 \(x\)\((p,q)\) 的出现次数为 \(b_x\)

由于中间的数字两两不同,那么每个数 \(x\)\(b_x\) 种选择,或者干脆不选。那么答案即为 \(\sum_{p<q} \prod_{c \ne a_p} (b_c+1)\),这个可以在 \(O(n^3)\) 时间内计算。

现在考虑如何计算最难算的 \(\sum k\)。考虑差分贡献,把贡献 \(k\) 拆分到 \(1 \sim k\) 每个上面。我们枚举 \(p,q\) 代表第 \(k'(k' \le k)\) 个前缀和后缀下标的位置。

因为贡献被拆分了,所以我们不关心 \(k'\) 的值,我们只需要知道每种 \(k'\) 的方案之和加起来即为答案。

观察到 \(p,q\) 并不存在偏序关系,不妨先考虑 \(p<q\) 怎么做,考虑限制:

选择若干个数,强制选定 \(p,q\),使得 \([1,p],[q,n]\) 中选择的数的个数相等,并且 \([1,p]\) 选择的数互不相同,\([q,n]\) 选择的数互不相同,对 \((p,q)\) 无限制。

中间的 \((p,q)\) 区间贡献系数显然为 \(2^{q-p-1}\),我们把 \([1,p]\) 选择的个数减去 \([q,n]\) 的个数看成下标进行背包。

不过由于 \([1,p]\) 可以全部放在 \([q,n]\) 前面,可以看作是若干体积为 \(1\) 的物品。物品的系数类似上面的 \([k=n-1]\)

这样做一次背包是 \(O(n^2)\) 的,枚举 \(p,q\) 也是 \(O(n^2)\) 的,这样是 \(O(n^4)\) 的难以通过。

不过可以固定 \(p\),观察到 \(q\) 移动时物品更改个数是 \(O(1)\) 的,那么就可以回撤背包做到 \(O(n^3)\) 了。

继续观察 \(p>q\) 怎么做,考虑限制:

选择若干个数,强制选定 \(p,q\),使得 \([1,p],[q,n]\) 中选择的数的个数相等,并且 \([1,p]\) 选择的数互不相同,\([q,n]\) 选择的数互不相同。

跟上面不同的地方在于,如果在 \((q,p)\) 中区间选定一个 \(a_i=x\),那么 \([1,q),(p,n]\) 都不能再选定 \(x\)。反之也是。

也就是说,这个背包对于一种物品,有三种选择(\(+1,0,-1\) 体积,价值均不同),直接做仍然是 \(O(n^4)\) 的。

考虑这个背包怎么回撤?注意到背包等于乘上一个有交换律的稀疏矩阵,对这个稀疏矩阵高斯消元即可,消一次是 \(O(n)\) 的。

或者换一种表达方式,\(g_i = \sum af_{i-1}+bf_i +cf_{i+1}\),那么 \(g_{n+1}\) 只会由 \(af_{n}\) 转移过来,可以解出 \(f_n\)\(g_n\)\(af_{n-1}+bf_{n}\) 转移而来,可以解出 \(f_{n-1}\),依次类推。

因为这是背包删除一组加入过的物品,这个方程组应该是一定有唯一解的,时间复杂度 \(O(n^3)\)

CF771E Bear and Rectangle Strips

首先显然可以注意到有用的矩阵最多只有 \(3n\) 个,先把这些矩阵提取出来。

有一个 \(O(n^2)\) 的 dp,设 \(f_{i,j}\) 代表第一行匹配到前 \(i\) 个,第二行匹配到前 \(j\) 个的答案。

仔细思考,发现有效的状态数非常少,题解有记搜但是不知道为啥正确。忽略宽度为 \(2\) 的矩形,我们考虑一种答案的生成方式:先选若干个第一行,再选若干个第二行,接着选若干个第一行,循环往复。

对于一个 \(i\),和 \(j \le i < nxt_j\),只需要记录 \(f_{i,j}\) 和取到最大值的最小的 \(j\) 即可。

该状态所有的导出状态都不优于取到最大值的状态的导出状态,因为如果答案少了 \(1\),往前再走一步一定劣于最大值的状态。

那么这个就可以 dp 了,时间复杂度 \(O(n \log n)\),对数在找矩阵时用的 map。

P7519 [省选联考 2021 A/B 卷] 滚榜

有显然的暴力 dp 做法,记录状态 \(S\),末尾编号,上一个 \(b\),目前的 \(\sum b\),复杂度非常高,应该是 \(O(2^n n^2 m^3)\)

考虑优化,发现关心的只有有多少个排列合法,而不是多少个操作序列合法,因此考虑如何判定合法。

题目的限制就是 \(b_i\) 升序,且 \(a_i+b_i\) 升序,改写限制:

\[b_x \le b_y \Leftrightarrow b_y-b_x \ge 0 \\ a_x + b_x\le a_y+b_y \Leftrightarrow a_x - a_y \le b_y - b_x \]

\(\Delta b\) 的下界应该就是 \(\max(0,a_x-a_y)\),因此最优的判定过程每次决策的 \(\Delta b\) 是固定的,于是可以直接去掉上一个 \(b\) 这一维,也就是设 \(f_{S,i,k}\) 代表状态为 \(S\),上一个为 \(i\)\(\sum b = k\) 即可,时间复杂度 \(O(2^n n^2 m)\)

P6836 [IOI 2020] 装饼干

判定型计数,先考虑判定过程,如何判定一个 \(y\) 是否合法。记 \(y = (y_{60}y_{59},...y_0)_2\),首先 \(y\) 的最低位要能填出来,也就是 \(x y_0 \le a_0\)。次低位也要能填出来,也就是 \(x(2y_1+y_0) \le 2a_1 + a_0\)

依次类推,则 \(\forall i \in [0,60)\),都需要满足 \(x \sum_{j \le i} 2^jy_j \le \sum_{j \le i} 2^ja_j\),移项得到 \(\sum_{j \le i} 2^jy_j \le \dfrac{\sum_{j \le i} 2^ja_j}{x}\)

不难发现,对于右边的每一项都是定值,记其为 \(s_j\)

我们考虑一个不知道怎么出来的 dp,记 \(f_{i,j}\) 代表考虑到第 \(i\) 位,\(\le i\) 的所有位加起来 \(\le j\) 的方案数。

显然 \(f_{i,s_i} = f_{i,j}(j>s_i)\),记 \(g_i = f_{i,s_i}\)。我们考虑 \(i\) 这一维选 \(1\) 或者选 \(0\)

  • \(0\):有转移 \(f_{i-1,j} \to f_{i,j}\)
  • \(1\)
    • 如果 \(j \ge 2^{i+1}-1\),那么这一位选不选都行,\(g_{i-1} \to f_{i,j}\)
    • 否则如果 \(j \ge 2^i\),那么有转移 \(f_{i-1,j-2^i} \to f_{i,j}\)

那么答案即为 \(g_{59}\)

第一眼感觉这个转移不太能做啊!但是分析发现,记搜 \(g_i\) 数组后,虽然每个 \(f\) 可能由一三情况同时转移而来,每个 \(f\) 最多只会递归到后面层的 \(O(k)\)\(f\),也就是直接 dfs 即可做到 \(O(qk^3)\)(我看到题解写的 \(O(qk^2)\),但是我不会证明)。

为什么是对的?如果一个 \(f_{i,j}\) 使得可以同时从 \(1,3\) 情况转移而来:

如果从 \(1\) 情况转移,那么下一层一定会满足 \(2\) 情况,并且之后的每一层都会满足 \(2\) 情况,层数是 \(O(k)\) 的。

如果从 \(3\) 情况转移,那么就会有递归子结构,只会有 \(O(k)\) 层,那么是 \(O(k^2)\) 的,总共这么算是 \(O(k^3)\) 的。

P8329 [ZJOI2022] 树

感觉非常有趣的题目,但是感觉我的水平不足以完全理解,把看到的一些思路全部记录下来。

视角一

发现我们钦定一个点是叶子节点是容易的,但是钦定一个点是非叶子节点是困难的,因为钦定一个点是非叶子节点后,难以维护后面这个点是否变成叶子节点。

首先的一个想法是直接记录还有多少个不合法的非叶子节点做 dp,这样是 \(O(n^5)\) 的。

另命题 \(P_i\) 代表 \(i\) 在第一棵树为叶子节点,\(Q_i\) 代表 \(i\) 在第二棵树为叶子节点,那么答案就是满足 \(P_i \land \neg Q_i=1\) 或者 \(Q_i \land \neg P_i=1\) 的方案数。记 \(f(S)\) 为满足限制 \(S=1\) 的方案数。

容斥,\(f(P_i \land \neg Q_i) = f(P_i)-f(P_i \land Q_i)\),另一种情况同理,也就是说贡献就等于 \(f(P_i)+f(Q_i)-2f(P_i \land Q_i)\)。注意这里的贡献应该是单步的。

\(f_{i,j,k}\) 代表考虑完 \((1,i)\) 所有点在第一棵树上的父亲,考虑完 \([1,i)\) 所有点在第二棵树上的父亲,第一棵树在 \([1,i)\)\(j\) 个无限制的节点,第二棵树在 \([i+1,n]\)\(k\) 个无限制的节点。

那么我们对于每个点,考虑其 \((P_i,Q_i)\) 的值。

  • \(P_i = 0\land Q_i=1\):那么在第二棵树上面无限制,前面有 \(j\) 个父亲选择,后面有 \(k\) 个父亲选择,\(f_{i-1,j,k} \times jk\to f_{i,j,k-1}\)
  • \(P_i=1 \land Q_i=0\):与第一种情况同理,\(f_{i-1,j,k} \times jk \to f_{i,j+1,k}\)
  • \(P_i=1 \land Q_i=1\):那么 \(i\) 在两棵树上都是叶子,\(f_{i-1,j,k} \times -2jk \to f_{i,j,k}\)

然后就做完了,时间复杂度 \(O(n^3)\)

视角二

\(f(S),g(S)\) 代表第一棵树,第二棵树非叶子节点恰好为 \(S\) 的方案数。

那么答案等于 \(\sum_{S \cup T=U,S\cap T=\varnothing} f(S)g(T)\)。设 \(f'(S),g'(S)\) 为第一棵树,第二棵树非叶子包含于 \(S\) 的方案,子集反演得到:

\[\sum_{S \cup T=U,S\cap T=\varnothing} f(S)g(T)=\sum_{S'\cap T'=\varnothing} f'(S)g'(T)(-2)^{n-|S|-|T|} \]

那么这个形式应该就是和上面是统一的了,同样维护即可,时间复杂度 \(O(n^3)\)

视角三

\(f(S)\)\(S\) 恰好为非叶子的方案数,\(f'(S)\) 为非叶子属于 \(S\) 的方案数,那么 \(f'(S)\) 容易表示:

\[f'(S)=\prod_{i=2}^n \sum_{j \in S}[j<i] \]

同样子集反演:

\[f(S)=\sum_{T \subset S,1 \notin T}(-1)^T f'(S \setminus T) \]

那么答案即为 \(\sum f^2(S)\),拆开平方:

\[\sum_S \sum_{T_1 \subset S} \sum_{T_2 \subset S} (-1)^{|T_1|+|T_2|} \prod_{i=2}^n(\sum_{j \in S \setminus T_1}[j<i])(\sum_{j \in S \setminus T_2}[j<i]) \]

这个形式也是好 \(O(n^3)\) 维护的,不是很能明白这个视角与前两个视角的本质区别,反正先抄下来吧。

P8294 [省选联考 2022] 最大权独立集问题

这个做法实在太牛了。转化问题:确定一个排列 \(p_{1 \sim n}\),使得 \(\sum \text{dist}(i,p_i) d_i\) 的值最小。

发现 \(p_{1 \sim n}\) 的置换环仅有一个,因为初始时 \(p_i=i\),每个点都是自环,每次交换就等价于合并两个环,进行 \(n-1\) 次合并后应该只剩一个环。

继续发现,从任意一条边切割开的两棵树,标号应该都对应环上的一个连续段,而且这个限制是充要的,也就是任意一个满足条件的排列都可以生成一个操作序列。

依据这个连续段的性质,我们对 \(p_i\) 进行 dp,记 \(f_{u,x,y}\) 代表考虑 \(u\) 子树,置换链起始点为 \(x\),终止点为 \(y\),只考虑链内部贡献的最小答案。

由于是二叉树,转移的时候,分类讨论,下记 \(A_i\) 为题目中的 \(d_i\)\(d_i\) 代表 \(i\) 的深度:

  • \(u\) 被两棵子树夹在中间:不妨设形如 \((s_1,t_1),u,(s_2,t_2)\),那么 \(f_{s_1,t_2} = \min(f_{s_1,t_1}+(d_{t_1}-d_u)A_{t_1}+(d_{s_2}-d_u)A_u+f_{s_2,t_2})\),转移意义很明显,即用 \(u\) 合并 \((s_1,t_1)\)\((s_2,t_2)\) 两条链并计算 \(t_1,u\) 的贡献。观察到前面两个和后面两个是独立的,分开维护即可。
  • \(u\) 被放在边上:不妨设形如 \(u,(s_1,t_1),(s_2,t_2)\),那么 \(f_{u,t_2} = \min((d_{s_1}-d_u)A_u+f_{s_1,t_1}+(d_{t_1}+d_{s_2}-2d_u)A_{t_1}+f_{s_2,t_2})\),维护也是简单的。

由于 \(\sum siz_{u,0} siz_{u,1}=O(n^2)\),所以时间复杂度是 \(O(n^2)\) 的,这个做法的代码非常好写,去掉缺省源只有 < 2K。

QOJ 10110. Not Another Constructive Problem

看着上一道题的题解去做的题目。

首先不妨设 \(p_i = 1 \sim n\),可以置换排列达到这个目的。

首先 \(q_i\) 的置换环只有一个,因为树上交换边,每次会合并两个环。其次对于每条边,两侧的编号都是连续的一段。我们记 \(b_i\) 代表 \(i\) 在置换环中的下标。

发现这个连续的限制,应该就是要求是张区间图。那么现在应该是一个经典题目了,直接套用 CF888F 的做法即可,时间复杂度 \(O(n^3)\)

[NOI2023] 桂花树

考虑第一个限制条件,就等价于 \(T'_{[1,n]}\) 的虚树刚好是 \(T\)

先考虑 \(n=1,k=0\) 的特殊性质该怎么做:考虑从小往大加入 \(n+1 \sim n+m\) 的所有点。对于 \(i\) 的限制是 \(\text{lca}(i,j) \le \max(i,j)+k\),枚举 \(j\),将限制改写为 \(\text{lca}(i,j) \le i+k(1 \le j < i)\)

那么此时对于 \(k=0\),限制就是 \(\text{lca}(i,j) \le i\),也就是说,\(i\) 塞进来后与每一个 \([1,i]\) 节点的 \(\text{lca}\) 都必须是 \([1,i]\) 的节点。也就是说,加入 \(i\) 只能塞在一条边里面或者一个点下面,贡献系数为 \((2(i-1)-1)\)

那么也就是说,对于 \(k=0\) 的答案即为 \(\prod_{n \le i < n + m}(2i-1)\)

我们考虑 \(k>0\) 的情况,怎么样生成一个不满足 \(\text{lca}(i,j) \le i\) 的点。那么此时应该是,\(x\)\(y\)\(\text{lca}\) 是一个 \(>\max(x,y)\) 的数。不妨设 \(x \le y\),那么我们在插入 \(y\) 的时候,把 \(\text{lca}(x,y)\) 插入 \(x\) 上方的一条边上,并且把 \(y\) 挂到这个点下方,即可生成这样一棵树。

由于 \(\text{lca}(x,y)-y \le k\),考虑状压,不妨进行一个类延后决策的东西。设 \(f_{i,S}\) 代表加入 \([1,i]\),后面 \(k\) 位是否被选择的状态为 \(S\)\(1\) 代表被延后决策填到某个点,从低到高位储存)。有转移:

  • \(S\) 为奇数,即下一位必须填到之前的某个点里面,\(f_{i,S} \to f_{i+1,S/2}\)
  • \(S\) 为偶数:
    • 直接把 \(i\) 插入到某条边或者某个点:\((2(i + \text{popc}(S))-1)f_{i,S} \to f_{i+1,S/2}\)
    • 选择直接加入两个点,新增一个待决策的点:\((i + \text{popc}(S)-1)f_{i,S} \to f_{i+1,S'}\)

那么就做完了,时间复杂度 \(O(mk2^k)\)

[未知来源] 禁止套娃

题意:求一个序列所有本质不同子序列的所有本质不同子序列的个数之和,\(n \le 5 \times 10^3\)

我们先考虑怎么算一个序列的本质不同子序列个数。钦定单射,只保留最左的方案。设 \(f_i\) 代表 \([1,i]\) 的答案,那么有转移 \(f_i = 2f_{i-1}-f_{pre_i-1}\)

记外面和里面选择的下标集合分别为 \(I,J\),那么因为单射有限制:

  • \(I\) 中相邻的两个数 \(i,i'\),不存在 \(j\in (i,i')\) 使得 \(a_{i'} = a_j\)
  • \(J\) 中相邻的两个数 \(j,j'\),不存在 \(k \in I \cap (j,j')\) 使得 \(a_{j'}=a_k\)

\(f_i\) 代表以 \(i\) 结尾且钦定 \(i\) 被选入 \(I,J\) 的方案数。考虑从 \(f_j\) 转移到 \(f_i\),记选择了 \(K \subseteq (i,j)\)。那么这个外层 dp 的意义其实是直接枚举了内层 \(J\) 的选择然后选择外层 \(I\)。我们考虑 \(K\) 的限制:

  • \(K\) 中相邻的两个数 \(k,k'\),不存在 \(c \in (k, k')\) 使得 \(a_{k'}=a_c\)
  • \(K\) 中最后一个数 \(k\),需要满足不存在 \(c \in (k,i)\) 使得 \(a_i=a_c\)
  • \(K\) 中不存在数 \(k \in (j,i)\) 使得 \(a_k=a_i\)

我们再把第二个限制容斥掉,记 \(g_{i,j}\) 代表满足 \(1,3\) 条件的子序列个数,这个就是最开始的引入问题,然后 \(f_j (g_{i,j} - g_{pre_i,j}) \to f_i\) 即可,时间复杂度 \(O(n^2)\)

QOJ 7793. [集训队互测 2023] 雷同

如果 \(x,y\) 节点合并,就新建一个节点 \(z\),然后这样就把合并过程描述成了一棵二叉树 \(T\)。记每个点的深度为 \(d_i\)

答案即为 \(f(T) + \sum w_id_i\)\(f(T)\) 代表二叉树磨损度的贡献。进一步描述,对 \(T\) 进行长剖,那么答案即为 \(\sum w_id_i + \sum_S 2^{d(S)} - 1\),其中 \(S\) 代表一条不是最长链的链,\(d(S)\) 代表 \(S\) 的长度。由于 \(|S|=n-1\),所以可以将 \(-1\) 提出来。

首先将所有物品的重量从小到大排序,那么深度必定不减。

考虑如果给定了深度序列 \(d_i\),那么怎么建树才是最优的。毫无疑问,重量的贡献已经算完了,只需要算磨损度的贡献即可。

从大往小扫深度 \(d\),现在我们会有若干个深度为 \(d\) 的叶子全部想要合并到 \(d-1\),也就是传递若干个链的长度到上一层,且这个长度是那一组的最大值。因为我们希望传递上去的长链尽可能短,也就是应该从大到小排序后相邻两个成一组,那么传上去的长链就是 \(1,3,5,...\) 的长链。

此时可以直接做 \(O(n^3 \log V)\) 的区间 dp 了。考虑怎么优化,下记 \(L(x)=\text{lowbit}(x)\)

先化简贡献函数,记这一层有 \(a\) 个叶子,下一层传上来 \(b\) 个节点,应该把 \(b\) 个节点放在前面,那么 \(a\) 个叶子的贡献就依次是 \(L(a),L(a+1),...,L(a+b-1)\)。这样算贡献可以直接提前算完一个叶子的所有贡献。

考虑一层一层做 dp,将 \(\sum w_id_i\) 按层拆掉。设 \(f_{i,j}\) 代表累计加入了 \(i\) 个叶子,当前还剩 \(j\) 个叶子的答案。需要注意的是这里不需要记层数,因为层数不重要。有转移:

  • \(f_{i,j} + L(j) \to f_{i+1,j+1}\):加入一个叶子并结算贡献。
  • \(f_{i,2j}+ \displaystyle\sum_{k=1}^i w_k \to f_{i,j}\):两两合并当前所有节点,向上走一层,然后给所有已经加入的节点 \(+1\) 深度。

那么答案就是 \(f_{n,0}-n+1\),时间复杂度 \(O(n^2)\)

CF1188C Array Beauty

终于有个我会做的了。 /ll

首先考虑答案应该不会很大,具体来说,由于鸽巢原理,答案的上界应该是 \(O(\dfrac{V}{k})\)

那么就可以枚举答案算了,考虑到恰好答案为 \(k\) 不太方便计数,拆开答案,拆成 \(\ge k\) 的答案。

那么就可以 dp 了,设 \(f_{i,j}\) 代表以 \(i\) 结尾选了 \(j\) 个的答案,转移时用个指针在加个前缀和即可做到 \(O(nk)\)

加起来时间复杂度 \(O(nV)\)

P8490 [IOI 2022] 鲶鱼塘

首先考虑一个暴力 dp,设 \(f_{i,j}\) 代表以 \(i\) 结尾,结尾的高度为 \(j\) 的答案

观察发现,这个 dp 的有效状态其实非常少。一列只有有鱼的下面的一个位置会成为状态,或者为空或者为满,这个可以调整证明。

但是还是不对,如果一条鱼被左右都覆盖到了,答案会算重。

继续观察到不存在 \(h_i \ge h_{i+1} \le h_{i+2}\),因为可以移除左右更矮的那一边让答案变大,所以放的柱子的形态一定是若干个单峰,对这个结构 dp 即可,时间复杂度 \(O(n) \sim O(n \log n)\)

题目很简单,代码感觉就很难写,先咕了。

posted @ 2025-11-10 21:46  nullpt3  阅读(7)  评论(0)    收藏  举报