正难则反

概述

以前学习计数 dp 时,总是见到 “正难则反” 的思想,这种思想在计数题中的确十分常用:如果合法的情况不好求,就求出全部情况以及不合法的情况,一减就能得出答案;求 恰好、至少 则需要用容斥,具体可以在这篇博客内查看。

但是,正难则反 的应用可不止局限于此,事实上,非常广泛,我认为:可以将表面的东西形容为 “正”,容易忽视的东西形容为 “反”,正难则反 则是对于 “反” 操作,这样说还是太抽象了,我们结合一些实际的例子进行理解。

DP 状态设计&转移优化

动态规划的状态设计,毫不夸张的讲,这是 dp 最重要的一步,万事开头难。为啥会用到这种思想,我们结合例题进行分析。

这类 dp 题目通常有如下特征:同一个数只能用 1 次,要维护巨大的集合但是时间不允许也做不到排除等效冗余。转移优化一般要贴近最终的状态,比如题目要求删除,那么最终状态是保留一些,我们处理保留的情况的值。还有一种经典的优化手段,在下面的下面的 T1 会讲到。

T1

[NOIP2021] 数列

不难注意到,题目问合法序列的方案数,也就是我们要填一个合法序列,如果依次考虑每一位填什么,容易发现不好转移,因为问题中存在进位,即:如果对于当前计算出的结果,随机的填上某个 2k ,根本计算不出会增加多少个 1,那么转移是失败的。

正难则反,如果考虑每个位置上填的数字不行,我们能不能考虑将每个数字填入位置,也就是反过来。

于是我们重新考虑进位的影响,容易发现,如果从小到大考虑每种数填的次数,那么进位是可以算出来的。可以参照下图:

4

不难发现,两个 1000 的进位是 1,可以直接传递到 10000 的计算中,因为两者仅仅相差一位,相当小学的竖式计算,所以我们从小到大依次考虑每种数填多少次,可以解决进位的问题。那我们就可以设状态了。

fi,j,k,l 表示现在填到第 i 位,考虑完了 202j,目前前一位的进位(如上图两个 1000 的进位)是 k,已经计算出 l1 的方案数。

接着,枚举 j+1 位填 t 个,于是,新的进位是 (t+k)>>1,这一位的数字是 (t+k)&1,所以有如下转移:

fi+t,j+1,(t+k)>>1,l+((t+k)&1)fi,j,k,l

边界条件:

f0,0,0,0=1

在转移的时候,还需要乘上权值,以及考虑放置位置,即盒子放球(可以出现空)的问题,这是显然的,不再赘述。

T2

给定一棵 n 个节点的树,顶点编号为 1,2,...,n,你需要给每个顶点设置一个标号 ci 满足:

  • 1cin
  • cicj(ij)
  • |cicj|2i,j 树上相邻)

求方案数。n60

按照题目的说辞,要给每个节点设置一个标号,如果我们直接考虑每个节点填什么,有两点比较麻烦:

  • 每个标号不能重复使用。如果不用 vis 等记录,怎么解决。
  • 相邻的节点标号差不能超过 2。如果记录每个点的父亲和自己填的什么,考虑子树进行转移,那么同样存在重复使用标号的问题。

无数困难暗示我们,此路不通。

正难则反,考虑每个标号填在那个节点。于是设出这样的状态:fi,p1,p2,S 表示现在将 1i 的标号都填好了,标号 i 填在 p1 节点上,标号 i1 填在 p2 节点上,现在填好的位置集合是 S

这样就可以转移了。具体的转移以及复杂度分析:戳这里

T3

[SDOI2008] 山贼集团

假如我们依次考虑每个分部的管理情况,其实不太好弄,毕竟计算贡献的时候,需要知道每个分部管理村落的交,必须要将所有村落的管理情况进行记录,但这在时间或空间上都是不允许的,于是我们转换思路,将 “多个分部同时管理一个村落” 改成 “一个村落同时被多个分部管理”。

fx,S 表示村落 x 被集合 S 管理所获得的最大贡献,是一个树形背包的形式,考虑这样转移:

fx,Sfx,T+fy,SxorTST

最后加上 xS 管理的贡献即可,可以用高维前缀和求得。

T4

现在有 n 个区间 [li,ri],每个区间有个权值 wi。我们把这 n 个区间当成 n 个点,如果两个区间有交(包括端点),就在这两个区间之间连边,形成了一个区间图。

现在希望删除一些区间,使得每个连通块大小不超过 k。输出删除区间最小的权值和。

这是一道关于转移优化的题目。

题目让删除一些区间,求删除的最小的权值和;显然可以反过来想,求保留的最大权值和。这样考虑问题会有好处(后面讲)。

我们考虑经过删除,所有区间长什么样:是一堆连续段,中间断开。我们发现,断开的位置恰好对问题进行了划分,所以考虑枚举断开的位置进行转移即可。转移方程式详见这里

至于好处,可以避免在边界处区间是否需要删除的讨论。


其他

T1

具体题目不记得了,大概是安排 a 的值,求下面式子的最值。

1lrnminlkrak×(rl+1)

一道 dp.

显然,如果对于每个区间直接计算最小值乘上区间长度,就变成枚举 a 的取值,直接算贡献,显然会超时。我们反过来想,对于位置 pap ,如果钦定他是最大值,那么可以影响多少个区间呢。

在区间 [l,r] 内,位置 p 除了 [l,p1][p+1,r] 不能影响,其他都能影响,所以我们可以直接计算出贡献,然后对于区间 [l,p1][p+1,r] 分别计算。这不就是区间 dp 吗。。。

dpl,r,k 表示区间最大值不能超过 k 的最大值的最值(因为钦定了一个最大值,所以区间内的其他值都必须小于等于这个值),于是可以这样转移:

dpl,r,k=dpl,p1,t+dpp+1,r,t+val

这样在原题可以拿到 48pts ,优化需要凸包,没学

但是空间上可能存在部分问题,如果不要 k 这一维关于最大值得限制,想想我们 dp 出来的值是否正确。

一种直观的想法是:如果不限制最大值,那么不能满足题目要求,计算出来的结果自然是错误的。我们举个例子,比如:对于中间的数 2 ,我们取了,获得了 2×num1 的贡献,不考虑最大值的限制,我们取了左边区间的 10 ,获得了 10×num2 的贡献,此时 num1>num2 显然成立。

对于这一段相同的区间,假设我们先取 10,并获得 10×num1 的贡献,再取 2 ,获得 2×num2 的贡献,这是合法的操作,并且 10×num1+2×num22×num1+10×num2 是显然成立的,也就是说,虽然在转移过程中虽然出现了不合法的决策,但是这一定不会成为最优解,也就不会影响答案的选取。

所以最终 dp 方程优化成:

dpl,r=dpl,p1+dpp+1,r+valap

空间复杂度骤降。。。

T2

给定一个由数字19组成的字符串 s,每次询问一个 10 位的由数字19?组成的模板串,求 s 中有多少个子串能匹配上该模板串。?可以匹配上任意数字。

例如,1?2?3可以匹配上1223319293,但是不能匹配12345

保证询问的模板串中至多有 4 个问号。

1n,q2×105

最暴力的想法肯定是先将 s 的所有长度为 10 的子串存下来,然后暴力填模板串的问号,直接进行匹配,由于最多有 4 个问号,所以时间复杂度是 O(n+q×104),可以通过 q 较小的数据。

有没有优化的方式呢,直接照着这个思路想貌似不太行,我们能否不处理模板串,转而预处理原串 s 呢(正难则反)?

显然可以,我们可以在对 s 的每个子串任意填上 4 个问号,储存起来,在查询的时候直接查找即可,时间复杂度是 O((104)n+q).

显然,两个都过不了

我们能否将 n,q 前面系数平衡一下?

我们考虑在 s 的每个子串任意填上 2 个问号,然后在模板串中暴力填上 2 个括号,进行匹配,这样时间复杂度就降为 O((102)n+q×102) ,使用手写哈希表储存,注意常数,可以通过此题。

T3

这是一类考虑权值不行,转而将权值进行排序,考虑下标的套路,但是题目不记得了,留坑代填。

Tobecontinue...

posted @   2017BeiJiang  阅读(96)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示