计数类 DP

P9522 [JOISC2022] 错误拼写

牛魔计数题使我旋转。

主要说一下分析思路:

根据字典序的比较方式我们可以转化一下 TAj<TBj 这个条件。我们现在只考虑严格小于的情况。

字典序暗示我们要从后往前 DP,于是设 fi,j 表示 si=j 的方案数。然后考虑从 fi,j 转移过来,思考转移的约束。

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

于是设 hj 表示 i+1nf,j 的贡献。每次移动 i 的时候更新 hj。用链表维护,时间复杂度 O(n||)

计数题好难。

P2051 [AHOI2009] 中国象棋

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

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

fi,j,k 表示前 i 行,有 j 列一个炮,有 k 列两个炮。

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

P3158 [CQOI2011] 放棋子

发现维护个数比较困难。

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

g 需要容斥。

P10982 Connected Graph

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

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

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

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

CF1989E Distance to Different

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

fi,j 表示前 i 个数分成了 j 个连续段的大小,转移不表,注意要特殊处理 fi2,j1

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

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

自己实在太唐了。

CF1585F Non-equal Neighbours

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

考虑容斥,钦定有 ki 满足 bi=bi+1,则 ans=k=0n1(1)kF(k)

于是有一个朴素的 DP,设 fi,j 表示前 i 个数,分成了 j 段的方案数,时间复杂度 O(n3)

然后发现我们需要的是段数的奇偶性,于是将状态改为 fi,0/1,时间复杂度 O(n2)

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

CF1909F Small Permutation Problem

很厉害的题。

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

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

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

[ARC180C] Subsequence and Prefix Sum

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

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

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

发现自己智力不够,思维混乱,我们只需再记录 gi 表示前面和为 i 且上一次为 0 的方案数。然后我们不用 fi1,0 转移到 fi,ai,这样就避免了选一个数的情况。然后用 gjfi,j+ai,就计算上了不止选一个数的情况。每次循环后,gaig0g0fi,0

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

P9131 [USACO23FEB] Problem Setting P

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

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

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

si,j 表示满足 x10 位是 i,后 10 位是 j 子集的 fx 的总和。那么转移的时候只需枚举前 10 位,修改 s 时只需枚举后 10 位。可以做到 O(n2m/2)

有一个大神 DP:考虑优化枚举子集,考虑每次加入一个元素,|S| 转移,从集合 ii{s1,s2,,sk}k! 种方式。

fi,j 表示现在走到集合 i,用了 j 步的方案。

  • 下一步走到的集合不选:fi{x},j+1fi,j
  • 下一步走到的集合选:fi{x},0fi,j×1(j+1)!×vali{x}

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

【NOIP Round #7】排列计数

很好的容斥 DP 题。

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

我们可以将一些连续的 |apiapi+1|=k 缩成一段,设 fi,j 表示将前 i 个子序列划分成 j 段的方案数,总答案就是 i=1n(1)niftot,i×i!

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

  • gi,j,0=gi1,j1,0+gi1,j1,1
  • gi,j,1=2×gi1,j,0+gi1,j,1

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

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

[ARC105F] Lights Out on Connected Graph

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

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

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

fs 表示 s 集合的答案,则 fs=gsft×gs/t。其中 gs 表示 s 集合连成二分图的方案数。

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

[ARC178D] Delete Range Mex

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

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

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

i 没被删,则 fl,r,ifmin(posi,l),max(posi+1,r),i1

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

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

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

[ARC176C] Max Permutation

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

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

ci 从小到大依次考虑每个联通块。每次是形如 Ascit 的贡献,t 是联通块点数。然后执行一次后缀减一。

不知道对不对。

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

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

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

[ARC169C] Not So Consecutive

fi,j 表示第 i 个 数填了 j。然后枚举连续段的起点转移。

第一个没填 j 的位置是可以直接找到的,记其为 p。则 k=pi1jjfk,jfi,j

时间复杂度 O(n2)

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

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

[ARC167C] MST on Line++

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

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

考虑如下的子问题:

|ij|kmax(pi,pj)A 时有边,求不形成环的情况下最多能选多少条边。

fi 表示 A=i 时的答案,第 i 条边被选的次数就是 fifi1

怎么求 fi?对于一个排列 P,将 Pji 的下标 j 放进集合 QQ 中元素升序排序。不在 Q 集合里的点一定没有任何连边。

而所有 QjQj1k 的下标之间都有连边,都选上一定不劣。所以一个排列 P 的贡献就是 j=2i[QjQj1k]

枚举一个 j,对所有排列计算贡献,QjQj1k 的排列有 K=1k(nKi1)×i!×(ni)! 个。再乘上 (i1) 即可。

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

[ARC067E] Grouping

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

fi,j 表示考虑了 i 个人,最后一组的人数为 j 的方案数。转移即枚举人数为 j 的组的总人数,k=1j1fi,j×(niki)×gki,(ki)/jfk,j。其中 gi,j 表示将 i 个人平均分成 j 组的方案数。

时间复杂度 O(n2lnn)

P2523 [HAOI2011] Problem c

tangsir题。

什么时候合法?就是 ai 的小于 nai+1 个,所以原始编号无关紧要,应该按 ai 从大到小考虑。

直接设 fi,j 表示编号 i 的有 j 个,转移即 fi,jfi+1,k×(jk)

P3255 [JLOI2013] 地形生成

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

按高度从大到小插入。

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

第二问,考虑将一段高度相同的山拿出来 DP。设 fi,j 表示该段前 i 座山插到前面的第 j 座山的前面。转移则 fi,j=fi1,j+fi,j1

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

二项式反演模板题。

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

a,b 从小到大排序,双指针求出 Ri 表示 b1Ri<ai

gi,j 表示前 i 个数至少有 jai>bi,转移则 gi,j=gi1,j+gi1,j1×(Ri(j1))

最后套二项式反演的公式,注意 gn,i 要乘上 (ni)!

posted @   xishanmeigao  阅读(13)  评论(0编辑  收藏  举报
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示