计数类 DP

P9522 [JOISC2022] 错误拼写

牛魔计数题使我旋转。

主要说一下分析思路:

根据字典序的比较方式我们可以转化一下 \(T_{A_j}<T_{B_j}\) 这个条件。我们现在只考虑严格小于的情况。

字典序暗示我们要从后往前 DP,于是设 \(f_{i,j}\) 表示 \(s_i=j\) 的方案数。然后考虑从 \(f_{i',j'}\) 转移过来,思考转移的约束。

这个约束就是对于一段 \([A,B]\) 里面的 \(i'\),对 \(i<A\) 都要少掉一段贡献,这段贡献和 \(j\) 有关。

于是设 \(h_j\) 表示 \(i+1\sim n\)\(f_{*,j}\) 的贡献。每次移动 \(i\) 的时候更新 \(h_j\)。用链表维护,时间复杂度 \(\mathcal{O}(n|\sum|)\)

计数题好难。

P2051 [AHOI2009] 中国象棋

即每一行、每一列最多有两个棋子。

在转移的时候,我们需要依赖于上一层的状态,但往往我们无需清楚每个地方的状态具体是啥,只需知道某种状态的个数,然后使用排列组合计算。

\(f_{i,j,k}\) 表示前 \(i\) 行,有 \(j\) 列一个炮,有 \(k\) 列两个炮。

枚举这一行放几个炮直接转移就行。

P3158 [CQOI2011] 放棋子

发现维护个数比较困难。

发现每种颜色都是相互独立的,区域的划分依据是完整的行和列。所以可以考虑设 \(f_{k,i,j}\) 表示前 \(k\) 种颜色占据了 \(i\)\(j\) 列的方案(这类题通常都可这样设),转移需要一个 \(g_{i,j,k}\) 表示用 \(k\) 枚同色棋子占据 \(i\)\(j\) 列的方案。

\(g\) 需要容斥。

P10982 Connected Graph

正难则反,我们求 \(n\) 个点的无向不联通图个数。

一开始为了不计算重复,我设了 \(f_{i,j}\) 表示 \(i\) 个点,形成 \(j\) 个联通块的方案,然后再它做容斥,但总有点问题。

一种可行的方法是:钦定一个点作为划分依据。

比如以 \(1\) 号点为依据,设 \(f_i\) 表示 \(i\) 个点的联通图方案,转移时考虑 \(1\) 号点所在联通块大小,让其余的点不与该联通块连边即可。

CF1989E Distance to Different

观察到 \(b\) 取决于 \(a\) 中相同数组成的连续段。

\(f_{i,j}\) 表示前 \(i\) 个数分成了 \(j\) 个连续段的大小,转移不表,注意要特殊处理 \(f_{i-2,j-1}\)

我想到这后还一直在想怎么保证每种数都填进去了这 \(j\) 个段,后来才发现只需保证分成了至少 \(k\) 个段就行了,具体怎么填根本不重要,因为对应的 \(b\) 都是一样的。

所以第二维只用开到 \(k+1\),前缀和优化。

自己实在太唐了。

CF1585F Non-equal Neighbours

感觉要记录 \(i\) 选的数和 \(a_i\) 的大小关系。然后可能可以转移??貌似没人这样做。

考虑容斥,钦定有 \(k\)\(i\) 满足 \(b_i=b_{i+1}\),则 \(ans=\sum\limits_{k=0}^{n-1}(-1)^kF(k)\)

于是有一个朴素的 DP,设 \(f_{i,j}\) 表示前 \(i\) 个数,分成了 \(j\) 段的方案数,时间复杂度 \(\mathcal{O}(n^3)\)

然后发现我们需要的是段数的奇偶性,于是将状态改为 \(f_{i,0/1}\),时间复杂度 \(\mathcal{O}(n^2)\)

发现转移式里不好优化的是一个 \(\min\),这个可以搞一个单调栈,然后加上一堆判断搞定。

CF1909F Small Permutation Problem

很厉害的题。

先考虑 Easy Version。一开始编了一个 DP 做法,但好像不太对。

第一步转化就是将 \((i,p_i)\) 放到坐标系上,将问题转化成放车问题,合法的放置要求每一行每一列都只有一个车。那么 \(a_i-a_{i-1}\) 就对应着一个 L 字形里的点对数量。实时维护 \((1,1)\sim(i,i)\) 还未放置的行列数量即可。

考虑 Hard Version,我们可以将一段 \(-1\) 缩起来,设区间 \((i,j)\) 之间全是 \(-1\),那么相当于在一个 \(y\times y\) 的网格挖掉左下角 \(x\times x\) 的网格后形成的 L 字形网格中放 \(t\) 个车,其中 \(x=j-a_j\)\(y=i-a_j\)\(t=a_i-a_j\)。这个东西可以容斥。时间复杂度 \(\mathcal{O}(n)\)

[ARC180C] Subsequence and Prefix Sum

发现 \(0\) 有很大的影响。发现第一个选的数也有很大影响(但这种可以归类为前面那种,因为初始值为 \(0\))。

一旦前缀和出现了 \(0\),后面如果只选一个数,那么跟不选没区别。如果选不止一个数,那么第一个数要是相同的选哪个都一样。怎么办?

一开始想用最小表示法,但不会 。

发现自己智力不够,思维混乱,我们只需再记录 \(g_i\) 表示前面和为 \(i\) 且上一次为 \(0\) 的方案数。然后我们不用 \(f_{i-1,0}\) 转移到 \(f_{i,a_i}\),这样就避免了选一个数的情况。然后用 \(g_j\to f_{i,j+a_i}\),就计算上了不止选一个数的情况。每次循环后,\(g_{a_i}\leftarrow g_0\)\(g_0\leftarrow f_{i,0}\)

反思:思维混乱,在计数题中是大忌。要学会归纳各种情况,减少复杂的分类讨论,规约为简单的问题。

P9131 [USACO23FEB] Problem Setting P

先考虑状压出每道题的状态,状态相同的单独考虑。然后思考转化判定条件:其实就是满足前一道题是后一题的子集。

那我们设 \(f_s\) 表示最后一道是 \(s\) 状态的题,枚举子集直接转移,时间复杂度 \(\mathcal{O}(3^m)\)

一个 Trick:将状压后的数折半,分成前后两部分。

\(s_{i,j}\) 表示满足 \(x\)\(10\) 位是 \(i\),后 \(10\) 位是 \(j\) 子集的 \(f_x\) 的总和。那么转移的时候只需枚举前 \(10\) 位,修改 \(s\) 时只需枚举后 \(10\) 位。可以做到 \(\mathcal{O}(n2^{m/2})\)

有一个大神 DP:考虑优化枚举子集,考虑每次加入一个元素,\(|S|\) 转移,从集合 \(i\to i\cup \{s_1,s_2,\dots,s_k\}\)\(k!\) 种方式。

\(f_{i,j}\) 表示现在走到集合 \(i\),用了 \(j\) 步的方案。

  • 下一步走到的集合不选:\(f_{i\cup \{x\},j+1}\leftarrow f_{i,j}\)
  • 下一步走到的集合选:\(f_{i\cup\{x\},0}\leftarrow f_{i,j}\times \dfrac{1}{(j+1)!}\times val_{i\cup \{x\}}\)

反思:转化判定条件,配合一些 Trick 的使用。

【NOIP Round #7】排列计数

很好的容斥 DP 题。

首先可以想到将极长的公差为 \(k\) 的子序列拿出来,然后容斥。

我们可以将一些连续的 \(|a_{p_i}-a_{p_{i+1}}|=k\) 缩成一段,设 \(f_{i,j}\) 表示将前 \(i\) 个子序列划分成 \(j\) 段的方案数,总答案就是 \(\sum\limits_{i=1}^{n}(-1)^{n-i} f_{tot,i}\times i!\)

考虑 \(f\) 的转移,我们发现长度 \(\ge 2\) 的段可以翻转,于是我们再设 \(g_{i,j,0/1}\) 表示将长度为 \(i\) 的子序列,分成 \(j\) 段,且最后一段 \(=1/\ge 2\) 的方案数。有:

  • \(g_{i,j,0}=g_{i-1,j-1,0}+g_{i-1,j-1,1}\)
  • \(g_{i,j,1}=2\times g_{i-1,j,0}+g_{i-1,j,1}\)

于是 \(f\) 的转移也容易写出。

反思:想到容斥之后没有往 DP 上想,也没有在缩成一段这个点上继续研究,而是想着上科技,或者硬着正面求解,淦!

[ARC105F] Lights Out on Connected Graph

考虑枚举左部点,然后计算联通的方案数。

但是不会计算!这个东西你一看还是容斥好嘛。

钦定那个编号最小所在的联通块和其他不联通,然后容斥。

\(f_{s}\) 表示 \(s\) 集合的答案,则 \(f_s=g_s-\sum f_t\times g_{s/t}\)。其中 \(g_s\) 表示 \(s\) 集合连成二分图的方案数。

反思:对容斥计数还是不熟悉,放到图上就想不到了。

[ARC178D] Delete Range Mex

看中文题面看错题了,看英文就发现看错了,怎么回事呢?

得仔细挖掘性质,首先删肯定是从大到小删。其次,要是想删掉一个数 \(i\),那么 \([0,i-1]\) 的数必须同时在 \(i\) 左边和右边。

然后我们时光倒流,考虑在空隙 \(1\sim m+1\) 里从小到大插入数。设 \(f_{l,r,i}\) 表示已经插入完了 \(0\sim i\) 的数,并且插在了 \(l\sim r\) 之间。

\(i\) 没被删,则 \(f_{l,r,i}\leftarrow f_{\min(pos_i,l),\max(pos_i+1,r),i-1}\)

若被删了,则分插在左右两边讨论,可以前缀和优化到 \(\mathcal{O}(1)\) 转移。

初始化分 \(0\) 是否被删讨论。

反思:需要努力挖掘性质的计数题,时光倒流,不太一样的区间 DP 写法。

[ARC176C] Max Permutation

还是建边,这样每个点只能满足最小的 \(c_i\)。一些点就确定了,剩下一些联通块。

因为是排列,所以每个 \(c_i\) 的联通块只能有一个而且是菊花图。记 \(s_i\) 表示剩下的 \(1\sim i\) 里的数的个数。

\(c_i\) 从小到大依次考虑每个联通块。每次是形如 \(A_{s_{c_i}}^t\) 的贡献,\(t\) 是联通块点数。然后执行一次后缀减一。

不知道对不对。

算了按别人的做法写一下吧。

首先仍然是建图,但我们现在考虑从 \(n\to 1\) 填数。在那个联通块里找到那个公共点,然后将 \(c_i\) 填到那个点上。其余的归到剩余点里。

反思:计算排列可以从填数角度入手。

[ARC169C] Not So Consecutive

\(f_{i,j}\) 表示第 \(i\) 个 数填了 \(j\)。然后枚举连续段的起点转移。

第一个没填 \(j\) 的位置是可以直接找到的,记其为 \(p\)。则 \(\sum\limits_{k=p}^{i-1}\sum \limits_{j'\ne j}f_{k,j}\to f_{i,j}\)

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

但是我写的太shi了,还过不去样例。不应该把 \(-1\) 拿出来单独做,应该直接在原序列做这样简便一点。

反思:要寻找实现简便的方式写代码。

[ARC167C] MST on Line++

将边权为 \(i\) 的边称为 \(i\) 类边。考虑每条边被选了几次。

考虑 kruskal 的过程,这只和边权的相对大小有关,所以将 \(a_i\) 升序排序。

考虑如下的子问题:

\(|i-j|\le k\)\(\max (p_i,p_j)\le A\) 时有边,求不形成环的情况下最多能选多少条边。

\(f_i\) 表示 \(A=i\) 时的答案,第 \(i\) 条边被选的次数就是 \(f_i-f_{i-1}\)

怎么求 \(f_i\)?对于一个排列 \(P\),将 \(P_j\le i\) 的下标 \(j\) 放进集合 \(Q\)\(Q\) 中元素升序排序。不在 \(Q\) 集合里的点一定没有任何连边。

而所有 \(Q_j-Q_{j-1}\le k\) 的下标之间都有连边,都选上一定不劣。所以一个排列 \(P\) 的贡献就是 \(\sum\limits_{j=2}^i [Q_j-Q_{j-1}\le k]\)

枚举一个 \(j\),对所有排列计算贡献,\(Q_j-Q_{j-1}\le k\) 的排列有 \(\sum\limits_{K=1}^k\binom{n-K}{i-1}\times i!\times (n-i)!\) 个。再乘上 \((i-1)\) 即可。

反思:步步紧凑的计数题,难度还是灰常大的。和某些算法要解决的问题相关的题目,可以从算法的过程入手。

[ARC067E] Grouping

按组的大小从小到大考虑。

\(f_{i,j}\) 表示考虑了 \(i\) 个人,最后一组的人数为 \(j\) 的方案数。转移即枚举人数为 \(j\) 的组的总人数,\(\sum\limits_{k=1}^{j-1}f_{i,j}\times \binom{n-i}{k-i}\times g_{k-i,(k-i)/j}\to f_{k,j}\)。其中 \(g_{i,j}\) 表示将 \(i\) 个人平均分成 \(j\) 组的方案数。

时间复杂度 \(\mathcal{O}(n^2\ln n)\)

P2523 [HAOI2011] Problem c

tangsir题。

什么时候合法?就是 \(\ge a_i\) 的小于 \(n-a_i+1\) 个,所以原始编号无关紧要,应该按 \(a_i\) 从大到小考虑。

直接设 \(f_{i,j}\) 表示编号 \(\ge i\) 的有 \(j\) 个,转移即 \(f_{i,j}\leftarrow f_{i+1,k}\times \binom{j}{k}\)

P3255 [JLOI2013] 地形生成

先考虑第一问,我以为第一问不能直接算答案,但其实是可以的。

按高度从大到小插入。

如果没有相同高度,则 \(ans\times \min(v_i,i)\to ans'\)。如果有相同高度呢?不妨按关键字从小到大排序,则 \(ans\times \min(v_i+t,i)\to ans'\)\(t\) 表示前面有多少个和它高度相同。

第二问,考虑将一段高度相同的山拿出来 DP。设 \(f_{i,j}\) 表示该段前 \(i\) 座山插到前面的第 \(j\) 座山的前面。转移则 \(f_{i,j}=f_{i-1,j}+f_{i,j-1}\)

P4859 已经没有什么好害怕的了

二项式反演模板题。

首先转化成恰好有 \((n+k)/2\)\(a_i>b_i\) 的方案数。

\(a,b\) 从小到大排序,双指针求出 \(R_i\) 表示 \(b_{1\sim R_i}<a_i\)

\(g_{i,j}\) 表示前 \(i\) 个数至少有 \(j\)\(a_i>b_i\),转移则 \(g_{i,j}=g_{i-1,j}+g_{i-1,j-1}\times (R_i-(j-1))\)

最后套二项式反演的公式,注意 \(g_{n,i}\) 要乘上 \((n-i)!\)

posted @ 2024-10-25 15:44  xishanmeigao  阅读(58)  评论(0)    收藏  举报