正难则反

概述

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

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

DP 状态设计&转移优化

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

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

T1

[NOIP2021] 数列

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

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

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

4

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

\(f_{i,j,k,l}\) 表示现在填到第 \(i\) 位,考虑完了 \(2^0\sim 2^j\),目前前一位的进位(如上图两个 \(1000\) 的进位)是 \(k\),已经计算出 \(l\)\(1\) 的方案数。

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

\[f_{i+t,j+1,(t+k)>>1,l+((t+k)\&1)}\Leftarrow f_{i,j,k,l} \]

边界条件:

\[f_{0,0,0,0}=1 \]

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

T2

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

  • \(1\le c_i \le n\)
  • \(c_i\ne c_j\;(i\ne j)\)
  • \(|c_i-c_j|\le 2\)\(i,j\) 树上相邻)

求方案数。\(n\le 60\)

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

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

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

正难则反,考虑每个标号填在那个节点。于是设出这样的状态:\(f_{i,p_1,p_2,S}\) 表示现在将 \(1\sim i\) 的标号都填好了,标号 \(i\) 填在 \(p_1\) 节点上,标号 \(i-1\) 填在 \(p_2\) 节点上,现在填好的位置集合是 \(S\)

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

T3

[SDOI2008] 山贼集团

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

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

\[f_{x,S}\Leftarrow f_{x,T}+f_{y,S\;xor\;T}\\ S\subseteq T \]

最后加上 \(x\)\(S\) 管理的贡献即可,可以用高维前缀和求得。

T4

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

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

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

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

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

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


其他

T1

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

\[\sum_{1\le l\le r\le n}\min_{l\le k\le r}a_k \times (r-l+1) \]

一道 \(dp\).

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

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

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

\[dp_{l,r,k}=dp_{l,p-1,t}+dp_{p+1,r,t}+val \]

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

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

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

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

所以最终 \(dp\) 方程优化成:

\[dp_{l,r}=dp_{l,p-1}+dp_{p+1,r}+val_{a_p} \]

空间复杂度骤降。。。

T2

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

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

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

\(1\le n,q\le 2\times 10^5\)

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

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

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

显然,两个都过不了

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

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

T3

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

\(To\;be\;continue...\)

posted @ 2022-11-22 16:28  2017BeiJiang  阅读(51)  评论(0编辑  收藏  举报