Loading

2025赛季做题记录-计数+dp

计数

【UR #1】外星人

归类:计数 dp

考虑到取模只会让数变小,所以从大到小模才有意义,先模小再模大数是没有意义的,因此考虑将数从大到小排序后顺序处理。

定义\(f_{i,j}\)表示考虑前\(i\)个数已经排好,使得现在的余数是\(j\)的方案数,考虑按照是否取模\(a_i\)分类转移。

如果要取模\(a_i\)那么就要紧接着,得到

\[f_{i-1,j}\rightarrow^+ f_{i,j\bmod a_i} \]

否则就要舍弃掉\(a_i\),将其扔到后面小数里,方案数为\((n-i)\),则

\[f_{i-1,j}(n-i)\rightarrow^+ f_{i,j} \]


[AGC013D] Piling Up

归类:计数 dp

考虑每次操作时的情况,取出的颜色与白球数量的关系:

  • WW 会使得数量 \(-1\)
  • WB 数量不变 \(0\)
  • BW 数量不变 \(0\)
  • BB 会使得数量 \(+1\)

所以每个出球序列都对应到一个白球数量的变化序列,因此可以得到一个dp:定义\(f_{i,j}\)表示考虑前\(i\)次操作,序列中剩下\(j\)个白球的变化序列的方案数。

但是我们需要考虑初始时的白球数量,很naive的想法就是钦定所有\(f_{0,*}=1\),但这是错误的。

因为不难发现,两个白球数量序列在初始数量不同时可能会得到相同的取出颜色序列,也就是算重了。

因此考虑处理冗余,我们可以将所有算重的白球序列都向下平移,映射到同一个与\(0\)相交的结果,那么只统计与\(0\)相交,即数量到达过\(0\)的白球操作序列即可。

所以改进dp,\(f_{i,j,0/1}\)表示考虑前\(i\)次操作,序列中剩下\(j\)个白球,当前是否触碰到\(0\) 的变化序列的方案数。简单转移即可。


P2612 [ZJOI2012] 波浪

归类:计数 dp

考虑拆贡献,考虑一个\(P_i\),如果左边小/大那么贡献就是\(\pm P_i\),右边小/大贡献就是\(\pm P_i\),所以我们关注的并不是每个\(P_i\)的具体位置,而是与其相邻的数的大小关系。

所以考虑从小到大填数,即可钦定数的大小关系,然后用连续段dp,令

\(f_{i,j,k,l}\) 表示填好了\(1\sim i\)的数,形成\(j\)个连通块,目前总贡献为\(k\),并且左右边界中有\(l\)个被使用的方案数。

分类讨论数\(i\)放在什么位置:

  • 不在边界上,且不与任何连通块相邻

    此时左右的数一定是比\(i\)大的,因此贡献为\(-2i\),有\((j+1)\)个空位,由于不能放在边界上,所以总共有\((j+1-l)\)种方案:

    \[f_{i+1,j+1,k-2i,l}\leftarrow^+ f_{i,j,k,l}(j+1-l) \]

  • 不在边界上,一端与连通块相邻 \((j\ge 1)\)

    此时一边大一边小,贡献为\(0\),每个连通块的左右都可以放,所以有\((2j-l)\)种方案:

    \[f_{i+1,j,k,l}\leftarrow^+ f_{i,j,k,l}(2j-l) \]

  • 合并两个连通块 \((j\ge 2)\)

    此时两边都是小,贡献为\(2i\),中间有\((j-1)\)个位置放,于是:

    \[f_{i+1,j-1,k+2i,l}\leftarrow^+ f_{i,j,k,l}(j-1) \]

  • 与边界相邻,且不与连通块相邻

    此时一边是大的,贡献为\(-i\),并且剩余\((2-l)\)个边界,于是:

    \[f_{i+1,j+1,k-i,l+1}\leftarrow^+ f_{i,j,k,l}(2-l) \]

  • 与边界相邻,且与连通块相邻 \((j\ge 1)\)

    此时一边是小的,贡献为\(i\),同理

    \[f_{i+1,j,k+i,l+1}\leftarrow^+ f_{i,j,k,l}(2-l) \]

最后概率就是\(\times \frac{1}{n!}\)


CF1821F Timber

归类:组合计数、容斥

每棵树会占据一个长度为 \(k+1\) 的区间,我们先考虑将这些区间放到 \([1,n]\) 中,也即,我们要在 \([1,n]\) 中放 \(m\) 个长度为 \(k+1\) 的区间。我们钦定一个区间的左端点为代表元,那么可以在放好代表元之后再把剩下的 \(k\) 个依次插到后面。所以可以放代表元的位置就有 \(n-mk\) 个,因此方案数就是 \(\binom{n-mk}{m}\)

确定好每棵树占据的区间,我们可以让这棵树向左倒/向右倒,所以每个有两种选择,选择方案数是 \(2^m\),于是我们很naive地认为总方案数是 \(\binom{n-mk}{m}\times 2^m\)

这是错的,因为可能有树既能往左倒也能往右倒,这在原来的统计方法中会被算 \(2\) 次,而题目中要求的是不同的种树方案,不同的倒下方案是不被统计的。

所以我们考虑容斥,减去既能往左倒也能往右倒的方案数。假设有 \(i\) 棵树可以往左和往右倒,我们可以将这棵树看做同时往左右倒,于是其占据了 \([x-k,x+k]\) 的位置,于是这棵树的区间比原来多 \(k\) 个占位,因此空位就有 \(n-mk-ik=n-(m+i)k\) 个,放区间方案数是 \(\binom{n-(m+i)k}{m}\)。这 \(i\) 棵树不能选择左右,对于其他的 \(m-i\) 棵树能选择左右,所以方案数为 \(2^{m-i}\)。从 \(m\) 个选 \(i\) 个,\(\binom{m}{i}\)。因此总方案数就是:

\[\binom{n-(m+i)k}{m}\times 2^{m-i}\times \binom{m}{i} \]

考虑容斥系数,本质是一个求并集的思想,所以容斥系数是 \((-1)^{i-1}\)

因此答案为:

\[\binom{n-mk}{m}\times 2^m-\sum_{i}(-1)^{i-1} \binom{n-(m+i)k}{m}\times 2^{m-i}\times \binom{m}{i} \]


P3978 [TJOI2015] 概率论

归类:组合计数

\(f_n\) 表示 \(n\) 个点二叉树的个数,\(g_n\) 表示 \(n\) 个点二叉树的叶子个数和。答案就是 \(\frac{g_n}{f_n}\)

叶子个数和不好求,我们考虑将【树的形态和其每个叶子】看做一个配对,那么 \(g\) 实际就是这个配对的数量。

考虑增量构造。假设现在有一个 \((n-1)\) 个点的二叉树,如果给这个二叉树加入一个点,并且这个点变成叶子结点,那么这棵新的树就可以和新增的叶子组成一个配对。\((n-1)\) 个点的二叉树总共有 \(2(n-1)\) 个槽,有 \((n-2)\) 个位置已经有点了,因此有 \(2(n-1)-(n-2)=n\) 个地方可以放叶子。所以总配对数量就是 \(f_{n-1}\times n\)

因此我们得到重要结论: \(g_n=f_{n-1}\times n\)

根据经典结论,\(f_n=\mathrm{Cat}_n=\frac{\binom{2n}{n}}{n+1}\)

所以

\[\frac{g_n}{f_n}=\frac{f_{n-1}\times n}{f_n}=\frac{\binom{2n-2}{n-1}}{\frac{\binom{2n}{n}}{n+1}} \\ = \frac{\binom{2n-2}{n-1}}{\binom{2n}{n}}\times (n+1)=\frac{n}{2(2n-1)}\times (n+1) \\ =\boxed{\frac{n(n+1)}{2(2n-1)}} \]


CF1523E

归类:组合计数、概率期望

看到贡献为 \(P(i)\times i\),用经典转化,定义 \(p_i\) 表示在 \(i\) 个台灯被点亮时仍然存活的概率,答案就是 \(\displaystyle\sum_{i=1}^{n} p_i+1\)

点亮 \(i\) 个台灯的总方案数就是 \(\displaystyle\binom{n}{i}\)。考虑怎么对合法方案计数,不难发现此时的必要条件为任意两个点亮的台灯之间至少有 \((k-1)\) 的间隔。

有这样几种计数方法:

  1. 把亮的台灯之间加入灭台灯看作放抽屉,就是 ...o...o...o...,先在中间的 \((i-1)\) 个空中每个放入 \((k-1)\) 个灭台灯作为保底,这样可以保证合法了,还剩下 \(n-(i-1)(k-1)\) 个灭台灯,放入 \((i+1)\) 个空位,插板法即可。

  2. 把每个亮台灯和其后面放的 \((k-1)\) 个灭台灯捆绑起来,这样考虑:先放好所有的亮台灯,然后再把后面的 \((k-1)\) 个灭台灯插到后面。为了保证放得下,亮台灯有 \(n-(i-1)(k-1)\) 个位置选择,方案数就是 \(\displaystyle\binom{n-(i-1)(k-1)}{i}\)

所以我们得到 \(p_i=\frac{\binom{n-(i-1)(k-1)}{i}}{\binom{n}{i}}\),直接计算,时间复杂度 \(O\left(\frac{n}{k}\right)\)


CF2119D

题解


[AGC061C] First Come First Serve

归类:计数 dp、容斥

每个人可以选择 \(a_i\)\(b_i\),并且选择时间点确定则相对顺序唯一确定,因此总方案数是 \(2^n\)。考虑这样统计会有什么问题:

    -----
---       ----

此时中间的区间选择 \(a_i\)\(b_i\) 是等价的,对于相对顺序没有影响,会算重,观察发现,选 \(a_i,b_i\) 等价,等价于 \([a_i,b_i]\) 没有其他时间点被选择。考虑容斥 dp,定义 \(f_i\) 表示前 \(i\) 个区间的相对位置方案数,显然第 \(i\) 个区间有两种选择,即 \(f_i\leftarrow 2f_{i-1}\),接着考虑容斥掉 \([a_i,b_i]\)。对于 \([a_i,b_i]\) 有影响的区间就是与其有交的,显然这是一段连续的,令 \(j,k\) 为最大的 \(b_j<a_i\)\(a_k<b_i\),则 \((j,k]\) 就是与 \([a_i,b_i]\) 有交的区间,由于区间没有包含关系,因此钦定这些区间都选到 \([a_i,b_i]\) 外面,即可使 \([a_i,b_i]\) 中的时间点为空,本质是令 \((j,k]\) 只有一种选择,这种情况下 \([a_i,b_i]\) 选在 \(a_i,b_i\) 是一样的,需要容斥掉,因此有转移:\(f_k\leftarrow^- f_j\),其含义是:在 \(k\) 处,有区间 \((j,k]\) 的一种选法使得 \(a_i\) 被算重,因此减去 \(f_j\) 以去重。而 \(j,k\) 可以双指针求出,时间复杂度 \(O(n)\)

P4099 [HEOI2013] SAO

归类:计数 dp、树上背包

外向树拓扑序计数:

\(n\) 个点的外向树拓扑序个数为:\(\dfrac{n!}{\displaystyle\prod sz_i}\)

证明:

从概率的角度考虑,即随机一个顺序是合法拓扑序的概率。充要条件就是每棵子树的根都在其内部点的前面,将其拎出来单独考虑,相当于钦定最靠前的是根,随机情况下概率就是 \(\dfrac{1}{sz_i}\),算在一起就是上式。

于是外向树的情况可以直接用子树大小计算,但是加入内向边就不好算了,此处考虑容斥。假设保留内向边集 \(S\) 内的边,并钦定这些边都不满足,即钦定这个边集中所有内向边都被改成外向边,且其他的内向边都被断掉。记其方案数为 \(F(S)\),则乘上容斥系数 \((-1)^{|S|}\) 后,答案就是 \(\displaystyle\sum_{S}(-1)^{|S|} F(S)\)

因此考虑一个树形 \(\mathrm{dp}\),定义 \(g_{u,i,j}\) 表示考虑 \(u\) 内的所有子树,包含 \(u\) 的连通块大小为 \(i\),钦定了 \(j\) 条内向边的方案数,最后方案数就是 \(\displaystyle\sum_{j} (-1)^j g_{u,i,j}\)。但是这个复杂度不对。不过注意到每次最多添加 \(1\) 条,所以可以将 \((-1)^j\) 这个容斥系数放进 \(\mathrm{dp}\) 里,定义 \(f_{u,i}\) 表示考虑 \(u\) 内的所有子树,包含 \(u\) 的连通块大小为 \(i\)乘上容斥系数的方案数。

考虑背包转移,对于一条边 \((u,v)\)

现在已经有长度为 \(sz_u\) 的拓扑序,可以按顺序随便插 \(sz_v\) 个,根据根据多重集的组合数是 \(cof=\dfrac{(sz_u+sz_v)!}{(sz_u)!(sz_v)!}\)

  • \((u,v)\) 为外向边

    没有任何特殊,直接并上一个 \(v\) 内部大小为 \(j\) 的连通块,因此得到转移:

    \[f^{\prime}_{u,i+j}\leftarrow \mathrm{cof}\times f_{u,i}f_{v,j} \]

  • \((u,v)\) 为内向边

    • 不把 \((u,v)\) 选入 \(S\)

      那么这条边相当于被断掉了,对联通块个数没有贡献:

      \[f^{\prime}_{u,i}\leftarrow \mathrm{cof}\times f_{u,i}f_{v,j} \]

    • \((u,v)\) 选入 \(S\)

      类似转移,不过此时乘上 \((-1)\) 的容斥系数:

      \[f^{\prime}_{u,i+j}\leftarrow (-1)\times \mathrm{cof}\times f_{u,i}f_{v,j} \]

最后背包完后,根据外向树的方案数,要乘上 \(u\) 所在连通块的 \(\dfrac{1}{sz_i}\),即 \(f_{u,i}\leftarrow f_{u,i}\times \dfrac{1}{i}\)


P13275 [NOI2025] 集合

题解


[ARC120F] Wine Thief

题解


[AGC012F] Prefix Median

分类:计数 dp

看到本质不同的 \(b\) 序列个数,转化为类似判定的问题,看看如何刻画一个序列 \(b\) 有办法合法,一般是挖掘要使 \(b\) 合法的等价(充要)条件。由于是中位数的问题,首先对 \(a\) 排序。

首先可以挖掘出一个比较显然的必要条件:\(b_i\in a_{[i,2n-i]}\)。证明:不妨设 \(b_i=a_j\),那么 \(j\) 左边和 \(j\) 右边要恰好选出 \((i-1)\) 个数,于是最左选到 \(i\),最右选到 \(2n-i\),因此 \(j\in [i,2n-i]\)

然后有一个 \(\texttt{observation}\)\(b_i\to b_{i+1}\),每次可选的数集会增加两个数,那么原来的中位数只可能【不变/变成前驱/变成后继】,等价于任意两个 \(b_i,b_{i+1}\) 之间没有夹着任何数,也即需要满足 \(\forall j,b_j\not\in (\min(b_i,b_{i+1}),\max(b_i,b_{i+1}))\)

我们声称,满足这两个条件就是充要的了。于是只需要对满足上述两个条件的 \(b\) 计数。

考虑定义 \(f_{i,l,r}\) 表示填好了后 \(i\) 个值,即确定了 \(b_{[n-i+1,n]}\),并且此时当前选择的位置左边还有 \(l\) 个空可以填,\(n\) 右边还有 \(r\) 个空可以填。考虑 \(b_{i+1}\rightarrow b_i\) 的方法,由于要有夹在中间的限制,讨论转移:

  • \(b_{i+1}=b_i\)

    此时中间没有限制,左边右边分别扩展一个空,得到 \(f_{i,x+1,y+1}\leftarrow f_{i+1,x,y}\)

  • \(b_{i+1}>b_i\)

    就是将 \(b_i\) 放在左边,限制 \((b_i,b_{i+1})\) 中不能填了,枚举这段区间用到的数的个数 \(j\),那么 \(b_i\) 左边就剩下 \((x+1-j)\) 个位置,右边扩展了一个空,并且 \(y\) 统计的是右边的个数,不包括 \(b_{i+1}\),此处加上 \(b_{i+1}\),个数变成 \((y+2)\),得到 \(f_{i,x+1-j,y+2}\leftarrow f_{i+1,x,y}\)

  • \(b_{i+1}<b_i\)

    同理,得到 \(f_{i,x+2,y+1-j}\leftarrow f_{i,x,y}\)

结束了吗?注意到 \(a_i\) 相同会造成答案算重,因为算出来的 \(b\) 是本质相同的。这种情况的去重方法就是考虑将值相同的 \(a_i\) 用位置区分开,于是在扩展时钦定相同的数只在第一次出现时统计,其他出现位置钦定不选即可。

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


CF53E Dead Ends

分类:计数 dp,状压 dp,去重

\(n\le 10\),考虑状压,如何设计状态?最直接的是 \(f_{S,k}\) 表示点集为 \(S\) 的生成树中叶子个数为 \(k\) 的方案数,不过我们发现这无法转移,因为接上的点可能会改变之前的叶子状态,于是改成记录叶子集合,\(f_{S,T}\) 表示叶子集合为 \(T\) 的方案数,即可每次加入一个点转移,得到:

\[f_{S\cup\set{u},\mathrm{trans}(T,v,u)}\leftarrow f_{S,T} \]

其中 \(\mathrm{trans}(T,v,u)\) 表示在 \(S\) 中的点 \(v\) 处接上一个点 \(u\) 后得到的新叶子集合。如果 \(v\in T\),接上 \(u\) 之后就不是叶子了,结果为 \(T\setminus \set{v}\cup \set{u}\),否则不受影响,结果为 \(T\cup \set{u}\)

但这是错的,因为和多数状压图计数一样,这样会算重,不难发现问题是叶子间接入的顺序是无关的,但在我们的统计中每增加一个叶子会被恰好计算 \(|T|\) 次,因此只需要用 \(f_{S,T}\times \dfrac{1}{|T|}\) 作为正确结果转移即可。也可以钦定顺序,钦定每次增加的叶子编号要递增即可。

时间复杂度 \(O(3^n n^2)\),可以通过。


P8340 [AHOI2022] 山河重整

归类:容斥、背包

题解


CF2134F Permutation Oddness

归类:组合计数、计数 dp

题解


\(\mathrm{DP}\)

P5280 [ZJOI2019] 线段树

归类:特殊 dp,概率期望

每次复制线段树的操作不好处理,但是线段树的形态是固定的,所以可以考虑求线段树上每个节点的贡献。

定义\(f_u\)表示线段树上点\(u\)的贡献,具体的,\(f_u\)表示在所有线段树中\(u\)处的\(\mathrm{tag}\)的期望值。

然后对于一次\(\mathrm{Modify}(l,r)\)操作涉及到的点分类讨论

  • 被完全覆盖的点(被打上此轮标记的点)

    这个点的\(\mathrm{tag}=1\)。当前的线段树会分成两份,其中一半会打上标记,所以得到转移:

    \(f_u\leftarrow \frac{1}{2}(f_u+1)\)

  • 被半覆盖且访问到的点(被主动\(\mathrm{pushdown}\)的点)

    这个点被执行了\(\mathrm{pushdown}\),所以肯定有\(\mathrm{tag}=0\),同理得到

    \(f_u\leftarrow \frac{1}{2}f_u\)

  • 完全没有被覆盖的点(可能被半覆盖的点下放到的点)

    这个点现在无法确定状态,因为不知道其祖先中是否有\(\mathrm{tag}\)会被下传到这个点。

所以我们还需要一个辅助\(g_u\),表示在下传时,点\(u\)的祖先中有\(\mathrm{tag}\)的概率。继续分讨计算\(g\)

  • 被完全覆盖的点(被打上此轮标记的点)

    \(\mathrm{tag}=1\),因此其子树中的所有点都有

    \(g_{v}\leftarrow \frac{1}{2}(g_{v}+1)\)

  • 被半覆盖且访问到的点(被主动\(\mathrm{pushdown}\)的点)

    其祖先的\(\mathrm{tag}\)一定已经下放,因此

    \(g_u\leftarrow \frac{1}{2}g_u\)

  • 完全没有被覆盖的点(可能被半覆盖的点下放到的点)

    取决于其祖先中是否存在有\(\mathrm{tag}\)的点被下放,如果有,那么就会堆在\(u\)处,因此\(g\)不变,\(f\)有变化:

    \(f_u\leftarrow \frac{1}{2}(f_u+g_u)\)

于是dp部分就完成了,\(f,g\)可以在遍历时修改。

注意到\(g\)需要在整棵子树中操作,所以需要打标记,若某个子树内需要进行\(p\)次子树操作,即\(x\leftarrow \frac{1}{2}(x+1)\),不难得到这个相当于\(x\leftarrow \frac{1}{2^p}x+\frac{2^p-1}{2^p}\),可以打标记实现。

最后每个点的贡献就是\(f_u\times cnt\),答案为\(\sum f_u\times cnt\)


P3592 [POI 2015] MYJ

归类:区间 \(\mathrm{DP}\)

关于最大/最小值的限制,考虑笛卡尔树,定义 \(f_{l,r,x}\) 表示考虑 \([l,r]\) 的洗衣店,其中价格的最小值 \(\ge x\) 的最大获利。可以不选 \(x\)\(f_{l,r,x}\leftarrow f_{l,r,x+1}\);选 \(x\),则用笛卡尔树的方法,直接枚举最小值 \(x\) 的位置 \(k\),考虑 \(x\) 目前会贡献到的洗衣店,其满足 \(l\le a_i\le k\le b_i\le r\),这些洗衣店都付 \(x\) 元,所以贡献为 \(cnt\times x\),得到转移: \(f_{l,r,x}\leftarrow \displaystyle\max_{l\le k\le r} \set{f_{l,k-1,x}+f_{k+1,r,x}+cnt\times x}\)

由于不关心 \(c_i\) 具体大小,可以离散化,\(x\) 一维大小是 \(O(m)\)\(cnt\) 可以做的时候预处理,时间复杂度 \(O(n^3m)\)


P13272 [NOI2025] 序列变换

题解


P3447 [POI 2006] KRY-Crystals

题解


CF1987F2 Interesting Problem (Hard Version)

分类:区间 \(\mathrm{dp}\)

删除数的过程不好刻画,不过我们可以考虑 \(a_i\) 和后面与其一起删除的数 \(a_j\),那么过程只能是 \(a_{[i+1,j-1]}\) 都被删空了,然后 \((a_i,a_j)\) 操作一次删除。这启发我们设计这样一个 \(\mathrm{dp}\),定义 \(f_{l,r}\) 表示要删空 \([l,r]\) 区间,至少要在 \([1,l-1]\) 中删除多少个数。转移考虑枚举与 \(a_l\) 一起删除的数 \(a_k,k\in [l,r]\),首先 \(a_l\) 要能够进行删除操作,这意味着要在 \([1,l-1]\) 中删除一些数,使得 \(a_l\) 对上其下标,不难发现前面需要删掉 \(l-a_l\) 个数,那么如果 \(l<a_l\vee l\not\equiv a_l\pmod 2\) 就寄了,否则就需要操作 \(v=\dfrac{l-a_l}{2}\) 次。然后我们需要删掉 \(a_{[l+1,k-1]}\),自然需要满足 \(l+1\equiv k-1\pmod 2\),并且由于 \(a_l,a_k\) 同时删除,所以在删除 \([l+1,k-1]\) 时前面恰好进行 \(v\) 次操作,否则 \(a_l\) 最终无法被删除,因此需要满足 \(f_{l+1,k-1}\le v\),删除这一段的操作次数就是 \(\dfrac{k-l+1}{2}\),剩下的一部分 \([k+1,r]\),要求 \([1,k]\) 的操作次数就是 \(f_{k+1,r}\),不过由于 \([l,k]\) 已经被删空了,所以只需要 \(f_{k+1,r}-\dfrac{k-l+1}{2}\) 次操作,得到最终的转移:\(f_{l,r}\leftarrow \max\left(v,f_{k+1,r}-\dfrac{k-l+1}{2}\right)\)

考虑最后如何求出答案。再用一个 \(\mathrm{dp}\),定义 \(g_i\) 表示 \([1,i]\) 的最多操作次数,可以不考虑 \(i\),有 \(g_i\leftarrow g_{i-1}\)。转移自然是考虑删掉一段区间 \([j,i]\),能删掉的条件就是 \(g_{j-1}\ge f_{j,i}\),有 \(g_i\leftarrow g_{j-1}+\dfrac{i-j+1}{2}\)

时间复杂度瓶颈在区间 \(\mathrm{dp}\),是 \(O(n^3)\) 的,不过因为转移时 \(k\) 只会枚举同奇偶,所以带小常数,可以通过。


[ARC130E] Increasing Minimum

分类:贪心

每次操作的限制就是全局 \(\min\),考虑将全局 \(\min\) 相同的操作划分为一段,即每段中操作的 \(A_{b_k}\) 都是相同的,这样,每段操作完成后,全局 \(\min\) 就会 \(+1\)。挖掘一下每段的性质,每次只能操作等于全局 \(\min\) 的数,所以每段中 \(b_k\) 都是互不相同的,并且除了最后一段以外,后一段的操作集合一定包含前一段的操作集合,因为等于最小值的集合只会扩张。不难发现满足这两个条件的划分方案就是合法的。考虑如何求出字典序最小的方案。

全局 \(\min\) 肯定是 \(1,2,\dots\) 往上加,那么从小到大每个数都尽可能多的填即可做到字典序最小。定义 \(f_i\) 表示在最优方案下划分 \(b_{[1,i]}\) 当前的的全局 \(\min\)。转移时,考虑 \([j,i]\) 表示 \(A_{b_{[j,i]}}\) 划分到同一段,那么限制就是 \(b_{[j,i]}\) 互不相同,并且 \(b_{[1,j)}\subseteq b_{[j,i]}\),此时有转移 \(f_i\leftarrow^{\min} f_j+1\),不过注意到可以直接取到 \(j\) 的最小值转移,即 \(f_i\leftarrow f_{j_{\min}}+1\)\(j_{\min}\) 可以简单求出。可以贪心找到最优的最后一段,然后逆推整个过程构出答案。


P3643 [APIO2016] 划艇

分类:dp优化、组合数学

定义 \(f_{i,j}\) 表示考虑前 \(i\) 所学校,且当前所有派出的个数最大值为 \(j\) 的方案数,分 \(i\) 派出和不派出,可以得到转移:

\[f_{i,j}\leftarrow f_{i-1,j} \\ f_{i,j}\leftarrow \sum_{k<j}f_{i-1,k},\quad \texttt{if } j\in [a_i,b_i] \]

状态数是 \(O(nV)\) 的,不能接受。此处压值域只能考虑离散化了,转变定义,\(j\) 表示最大值落在 \([pos_j,pos_{j+1})\) 区间。这样会得到转移:

\[f_{i,j}\leftarrow (p_{j+1}-p_j)\times \sum_{k<j} f_{i-1,k} \]

但这是错的,因为我们没有考虑同一个区间内的情况,何意味?用 \(\ell\) 表示区间长度,假设有 \(x\) 个数落在这个区间中,那么按顺序填完的方案数是 \(\dbinom{\ell}{x}\),而非单纯的 \((pos_{j+1}-pos_j)\) 转移。所以我们再记录一个有几个数落在 \(j\) 区间中,用 \(f_{i,j,k}\) 表示考虑前 \(i\) 所学校,当前派出的个数最大值落在 \([pos_j,pos_{j+1})\),且这个区间中已经填了 \(k\) 个数。那么可以不派出 \(i\),得到 \(f_{i,j}\leftarrow f_{i-1,j}\);如果派出 \(i\),可以继续分到这个区间中,原来的贡献系数是 \(\dbinom{\ell}{k-1}\),现在加一个变成 \(\dbinom{\ell}{k}\),相当于 \(\times \dfrac{\ell-k+1}{k}\);也可以新开一个区间,在新的区间内有 \(\ell\) 种选法。综上,得到:

\[f_{i,j}\leftarrow f_{i-1,j} \\ \texttt{if } [p_j,p_{j+1})\subseteq [a_i,b_i]: \\ f_{i,j,1}\leftarrow \sum_{p<j,k} f_{i-1,p,k}\times \ell \\ f_{i,j,k}\leftarrow f_{i-1,j,k-1}\times \dfrac{\ell-k+1}{k} \]

使用前缀和简单优化一下,时间复杂度 \(O(n^3)\)


UOJ【UR #13】Ernd

归类:二维偏序、斜率优化

先考虑暴力的 \(\mathrm{dp}\)。贡献与每一个连续段长度有关,分段进行 \(\mathrm{dp}\),定义 \(f_i\) 表示在必选第 \(i\) 个水果时的最大收益。转移时枚举区间 \([j,i]\) 为极长的连续段,则再另 \(g_i\) 表示一定不选第 \(i\) 个水果时的最大收益,得到转移:

\[f_i=\max_{\mathrm{pass}(j,i)}\set{g_j+(i-j+1)^2} \\ g_i=\max_{j\rightsquigarrow i}\set{f_j} \]

可以做到 \(O(n^2)\)。需要优化。

先优化 \(g_i\) 的计算,\(j\rightsquigarrow i\) 等价于 \(|a_i-a_j|\le b_i-b_j\),考虑如何拆掉这个绝对值,如果按 \(a_i,a_j\) 大小关系分讨就不好处理,但注意到我们有 \(|a_i-a_j|=\max(a_i-a_j,a_j-a_i)\le b_i-b_j\),因此可以拆成两个限制:

\[\left\{\begin{aligned} a_i-a_j &\le b_i-b_j \\ a_j-a_i &\le b_i-b_j \end{aligned}\right. \\ \Rightarrow \left\{\begin{aligned} b_j-a_j &\le b_i-a_i \\ a_j+b_j &\le a_i+b_i \end{aligned}\right. \]

看似我们将其做到了一个二维偏序的形式,但是还有 \(j\le i\) 的限制。不过再次注意到,由于 \(|a_i-a_j|\ge 0\),所以有 \(b_i-b_j\ge |a_i-a_j|\ge 0\),即 \(b_i\ge b_j\Rightarrow j\le i\)。所以只是一个二维偏序,因此可以扫描线+树状数组解决。

现在需要优化 \(f_i\)\(g_j+(i-j+1)^2\) 的转移,由于是取 \(\max\),所以这个东西是可以斜率优化的,但是还有 \(\mathrm{pass}(j,i)\) 的限制。不过注意到 \(\mathrm{pass}([l,r])\) 实际构成了一个个连续段,因此每个 \(i\) 只会从一个连续段中转移,对当前扫到的连续段维护凸包转移即可。

时间复杂度 \(O(n\log n)\)


CF1773G Game of Questions

归类:状压 dp,概率期望

题解


[AGC013E] Placing Squares

厉害题。

代数(\(\mathrm{dp}\))做法

不难想到一个 trivial 的 \(\mathrm{dp}\)\(f_i\) 表示考虑前 \(i\) 个格子放正方形的总贡献,令 \(S=\set{a_i}\),容易得到转移 \(f_i=\displaystyle\sum_{j<i\wedge j\not\in S} f_j\times (i-j)^2\),为了简化转移,等价变换为 \(f_i = [i\in S]\times \displaystyle\sum_{j<i} f_j(i-j)^2\)

可以简单优化到时间复杂度 \(O(V)\),无法通过。注意到如果没有 \(S\) 的限制,即相邻两个 \(a_i\) 之间的部分,其转移都是固定的 \(\sum f_j\times (i-j)^2\) 形式,考虑快速计算这部分,不难想到矩乘,套路地寻找 \(f_i\)\(f_{i+1}\) 之间的关系,直接展开 \(f_{i+1}\),得到:

\[\begin{aligned} f_{i+1} &=\sum_{j=0}^{i} f_{j}\cdot (i-j+1)^2\\ &= f_i+\sum_{j=0}^{i-1} f_{j}\cdot (i-j+1)^2 \\ &= f_i+\sum_{j=0}^{i-1} f_{j}\cdot \left[(i-j)^2+2(i-j)+1\right] \\ &= f_i+\sum_{j=0}^{i-1} f_{j}\cdot (i-j)^2+2\times \sum_{j=0}^{i-1} f_j\cdot (i-j)+\sum_{j=0}^{i-1}f_j \\ &= f_i+a_i+2b_i+c_i \\ \end{aligned} \]

于是我们需要找出 \((a_i,b_i,c_i)\to (a_{i+1},b_{i+1},c_{i+1})\) 之间的递推关系。不难发现 \(a_i=f_i\),以此为基准:

\[\begin{aligned} a_{i+1} &=f_{i+1}=f_i+a_i+2b_i+c_i=2a_i+2b_i+c_i \\ b_{i+1} &= \sum_{j=0}^{i} f_j\cdot (i-j+1) \\ &= f_i+\sum_{j=0}^{i-1} f_j\cdot (i-j+1) \\ &= f_i+\sum_{j=0}^{i-1} f_j\cdot (i-j)+\sum_{j=0}^{i-1}f_j \\ &= a_i+b_i+c_i \\ c_{i+1} &= c_i+f_i=c_i+a_i \end{aligned} \]

如果限定 \(f_i=0\) 也同理,不难得到 \(a_{i+1}=a_i+2b_i+c_i,b_{i+1}=b_i+c_i,c_{i+1}=c_i\)

于是我们发现上述递推式都可以用矩阵 \([a_i,b_i,c_i]\) 表示,转移矩阵对应:

\[\left\{\begin{matrix} a_{i+1} = 2a_i+2b_i+1c_i \\ b_{i+1} = 1a_i+1b_i+1c_i \\ c_{i+1} = 1a_i+0b_i+1c_i \end{matrix}\right. \Rightarrow \begin{bmatrix} 2 & 1 & 1 \\ 2 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix}=A \\ \left\{\begin{matrix} a_{i+1} = 1a_i+2b_i+1c_i \\ b_{i+1} = 0a_i+1b_i+1c_i \\ c_{i+1} = 0a_i+0b_i+1c_i \end{matrix}\right. \Rightarrow \begin{bmatrix} 1 & 0 & 0 \\ 2 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix}=B \\ \]

其含义为在不限定 \(f_i=0\),即 \(i\not\in S\) 时转移矩阵为 \(A\),否则转移矩阵为 \(B\)。因此可以在 \((a_i,a_{i+1})\) 之间用矩阵快速幂乘上 \(A\) 的幂,\(a_i\) 处乘上 \(B\) 即可。时间复杂度 \(O({\omega}^3n\log V)\),可以通过。不过由于每次乘上的都是固定的矩阵 \(A\),所以可以预处理 \(A^{2^k}\),询问时由于矩阵乘有结合律,可以二进制拆分后一个一个往后乘,一维矩阵乘法在每一行本质是一个矢量乘向量,可以做到 \(O({\omega}^2)\),于是可以 \(O({\omega}^3\log V)\) 预处理,\(O({\omega}^2\log V)\) 做单次,时间复杂度 \(O\left({\omega}^3 \log V+n({\omega}^2\log V+{\omega}^3)\right)\),不过由于 \(\omega=3\) 过小,没有什么优化价值。

组合意义做法

可以将放满正方形看做用隔板隔开空间,套路地,考虑平方的组合意义,可以看做每段中放两个颜色不同的球的方案数,其就是 \({\ell}^2\),所以可以对每一段设计这样的 \(\mathrm{dp}\)\(f_{i,0/1/2}\) 表示考虑前 \(i\) 个位置,这段已经放置了 \(0/1/2\) 个小球的方案数,转移是简单的此处不赘述,其同样可以用矩阵快速幂优化,时间复杂度相同。


P12196 [NOISG 2025 Prelim] Lasers 2

考虑刻画出合法方案的形态和充要条件,再用 \(\mathrm{dp}\) 来最优化。

最终锁覆盖的一定是若干个不交的非空极长连续段,记这些连续段为 \([L_1,R_1],\dots,[L_k,R_k]\),其合法的充要条件是什么?限制最强的是最长的锁,其他的锁都可以缩到这个锁的区间里,记其长度为 \(\ell=\max\set{r_i-l_i+1}\),则合法等价于存在 \(R_i-L_i+1\ge \ell\)。并且还有代价的限制,直接追踪哪些区间解锁显然不好做,正难则反,考虑有哪些区间不需要解锁,由于各个连续段不交,所以可以对每个连续段统计,记 \(w(l,r)\) 表示满足 \([l_i,r_i]\in [l,r]\) 的锁 \(c_i\) 之和,则不需要动的锁代价和为 \(\sum w(L_i,R_i)\),需要动的锁代价和自然就是 \(\sum c_i-\sum w(L_i,R_i)\)。综上,我们可以得到连续段方案合法等价于:

\[\boxed{\exists i,s.t.\enspace R_i-L_i+1\ge \ell} \wedge \boxed{\sum c_i-\sum w(L_i,R_i)\le k} \]

接下来就是用 \(\mathrm{dp}\) 来求解。有两种方向,可以考虑固定使用代价下的最大空位,也可以考虑固定空位下的最少代价,由于代价范围过大,因此选取后者,在固定空位数量下对最少代价 \(\mathrm{dp}\),代价可以看做最大化 \(\sum w(L_i,R_i)\),因此设计状态 \(f_{i,j,0/1}\) 表示考虑前 \(i\) 列,有 \(j\) 列空着,目前是否有 \(R_i-L_i+1\ge \ell\) 的连续段出现,此时 \(\sum w(L_i,R_i)\) 的最大值。转移分第 \(i\) 列的状态讨论:

  • \(i\) 列留空 \(f_{i,j,o}\leftarrow f_{i-1,j-1,o}\)

  • \(i\) 列作为某个连续段右端点出现 \(f_{i,j,o\vee [i-l+1\ge \ell]}\leftarrow f_{l-1,j,o}+w(l,i)\)

直接暴力枚举 \(l\) 转移时间复杂度 \(O(m^3)\),无法通过。\(j,o\) 处的变化可以简单处理,转移的本质是 \(f_i=\max \set{f_{l-1}+w(l,i)}\),考虑对 \(i\) 扫描线时在线段树上对每个 \(l\) 动态维护 \(w(l,i)\),具体的加入 \(r=i\) 的区间并线段树上区间加,维护 \(\max\) 即可,此处不再赘述。

时间复杂度 \(O(m^2\log m)\)


[WC2021] 表达式求值

直接整个数组作为主体来考虑显然是不好的,由于都是求和所以可以直接对每列拆贡献,看做求 \(n\)\(m\) 个变量的总和,考虑第 \(k\) 列,将 \(A_k\) 记为 \([a_0,a_1,\dots ,a_{m-1}]\)。由于牵扯到大小关系且值域较大,继续拆,考虑每个变量 \(a_i\) 作为答案的方案数。原表达式中的 \(0\sim 9,\texttt{?}\) 可以看做是 \(a\) 中的一个数,套路地建立表达式树并考虑 \(\mathrm{dp}\) 出方案数,定义 \(f_{u,0/1}\) 表示考虑表达式树的 \(u\) 子树内部,目前得到的结果是 \(<a_i\) 还是 \(\ge a_i\) 的方案数,转移是简单的。但是重新审视复杂度,这样每做一列都要枚举每个数、遍历一遍表达式树,时间复杂度其实是 \(O(nm|E|)\) 的,退化成暴力了。怎么会是呢?

我们注意到每一列的 \(\mathrm{dp}\) 过程实际上是很相似的,这样对每一列都跑一遍就浪费了很多信息,具体来挖掘一下,我们发现其实每次的具体数值是不重要的,大小才是有用的,决定某个 \(a_i\) 方案数的因素只有 \(a\) 中比 \(a_i\) 小的集合。我们发现这样可以做了,定义 \(f_{S,u,0/1}\) 表示钦定比 \(a_i\) 小的集合为 \(S\),考虑表达式树的 \(u\) 子树内部,目前得到的结果是 \(<a_i\) 还是 \(\ge a_i\) 的方案数,转移分讨一下:

  • \(u\) 是叶子,对应下标 \(p\)。 那么若 \(p\in S\) 则结果要小于 \(a_i\)\(f_{S,u,0}=1\),否则 \(f_{S,u,1}=1\)

  • \(s_u=\texttt{<}\)\(\texttt{>}\),对应 \(\oplus=\min,\max\) 操作

    \[f_{S,u,\oplus(i,j)}\leftarrow f_{S,lc,i}\times f_{S,rc,j} \]

  • \(s_u=\texttt{?}\),对应 \(\min,\max\) 操作方案数的和。

因此可以 \(O(2^m|E|)\) 做完这个 \(\mathrm{dp}\)。考虑如何求答案。

\(a\) 排序后,记 \(S=\set{p_1,\dots,p_{i-1}}\),则 \(\ge a_i\) 的方案数 \(F(i)=f_{S,rt,1}\)。但是我们想要 \(=a_i\) 的方案数,这个简单,直接容斥掉即可,即 \(=a_i\) 的方案数为 \(F(i)-F(i+1)\),因此贡献就是 \(\displaystyle\sum_{i\in [0,m)}[F(i)-F(i+1)]\times a_i\)。求个和就得到答案,总时间复杂度 \(O(2^m |E|+nm)\)

体现了一种信息重复利用(?)的思想。


P8916 [DMOI-R2] 暗号

归类:树形 dp,拆贡献

题解


P13714 淘汰(Hard ver.)

既有 \(\wedge\) 又有 \(\vee\),数字变化不具备拓扑序,并且每个决策可以用多次,转移也不满足拓扑序,因此直接在值域上 \(\mathrm{dp}\) 是不可行的。可以建出图跑最短路,经过优化后可以做到 \(O(3^k k)\),不是很优秀。

挖掘一下 \(\wedge,\vee\) 的性质,我们发现 \(\mathrm{bit}\wedge 1\) 是没有意义的,因此 \(\wedge\) 其实是将某些特定的位覆盖成 \(0\),同理 \(\mathrm{bit}\vee 0\) 是没有意义的,\(\vee\) 其实是将某些特定的位覆盖成 \(1\),因此这两个操作可以看做是推平操作。考虑到我们的目标是 \(X\to Y\),拆位,注意到每一位的变化方式一定是从某一时刻开始变到和 \(Y\) 相同,然后钦定后面不会发生变化,我们发现这其实是一个被确定集合不断扩展的过程,于是我们对着这个设计 \(\mathrm{dp}\),考虑令 \(f_{S}\) 表示现在位集合 \(S\) 中的数已经被固定住了,且其他位任意的最小代价。注意此时我们并不关注 \(S\) 以外的位具体是什么,因为推平操作并不依赖于原来的值。并且一旦我们知道 \(S\) 集合已经固定,则 \(S\) 中的数也可以通过取出 \(Y\) 中的对应位得到。

转移考虑每次新增一个集合 \(T\) 被固定住,以 \(\wedge\) 为例,其作用是覆盖某些位置为 \(0\),记这个覆盖集合为 \(s_i\),代价为 \(w_i\),则此时 \(Y\)\(T\) 中对应的位显然都应该是 \(0\),并且为了让 \(s_i\) 能够盖住 \(T\),所以要求 \(T\subseteq s_i\),同时注意原来集合 \(S\) 中的 \(1\) 不能被覆盖成 \(0\),记 \(S\)\(Y\) 中为 \(1\) 的集合为 \(S_1\),则要求 \(s_i\cap S_1=\varnothing\)。因此有转移:

\[f_{S\cup T}\leftarrow f_{S}+w_i\quad (T\subseteq s_i\wedge s_i\cap S_1=\varnothing) \]

并且 \(\vee\) 可以同理转移。不难在 \(O(3^k)\) 或者 \(O(2^k k)\) 的时间复杂度提前处理出 \(w_i\) 的最小值,因此总时间复杂度为 \(O(3^k)\),且常数很小,可以通过。

posted @ 2025-11-17 09:25  STDJCY  阅读(14)  评论(0)    收藏  举报