几个基本trick
LIS 的 O(n log n) 解法
LIS 也就是 f[i] 表示以 i 为结尾的最优答案, 原数列为 a。
首先可以直接用树状数组优化一下转移的复杂度, 这个方法比较naive就不说了。
另一种方法的话, 是维护一个 g 数组, 用 g[i] 记录 f 值为 i 的最小 a 值, 易证 g[1] <= g[2] <= …… <= g[n]。
用这个数组就可以很好地优化转移, 具体细节不赘述。
这个方法写起来相比树状数组方法更加短, 并且无需离散化。
Dilworth定理
满足:
自反性, 即 \(a\le a\)
反对称性, 即 \(a\le b, \; b\le a \; \to a = b\)
传递性, 即 \(a\le b, \; b\le c \to a \le c\)
的 \(A\) 上的二元关系 \(\le\) 称为偏序关系, 此时 \((A,\le)\) 就是一个偏序集。
一个 \(A\) 的子集, 满足任意两个元素之间都有偏序关系, 就称这个子集为这个偏序集的一条 链。
一个 \(A\) 的子集, 满足任意两个元素之间都有偏序关系, 就称这个子集为这个偏序集的一条 反链。
Dilworth定理的内容:
对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目
枚举子集
for(int S0=S; S0; S0=(S0-1)&S)
表达上的小 trick
- 目标是先最小化 v1 再最小化 v2, 可以定义一个 M, 把目标转化为最小化 v1*M + v2, 使得不论 v2 相差多少, 只要 v1 小, 就一定小。
- 待更
思维上的小 trick
- 减小答案集合。
例1:POJ3666, 可以在 acwing 上找到, 题号是 273.
这道题 yxc 有详细的视频讲解, 我不在这里叙述了。
例2:JOI Open 2019 T1, 在 loj 上有翻译和数据, 链接在此。
这道题的一种做法的第一步就是缩小答案集合。
小结: 这类方法有各种效果。 - 对应
其实我还没见过很多这种 trick。 这种 trick 大概就是把状态空间里的东西跟状态空间外的东西一一对应或者在状态空间里面一一对应,通常可以让生活变得更轻松。
例1: 组合数的对称。 也就是 \(\binom{r}{k} = \binom{r}{r-k}\)。 从组合意义上理解就是从 r 个元素中选出 k 个元素相当于从 r 个元素中选出 r-k 个元素不选。
例2: 最长公共子序列问题。 可以把选出一个最长的公共子序列看成可以把两个序列分别去掉若干元素, 使得两个序列相等且长度最长, 这样就可以比较简单地理解这个问题的状态转移方程。(其实还有一种理解方法, 关键点是用类似 LIS 的思考方式看待 LCS 的方程和:(1,0)和(0,1)两个向量的线性组合可以组成任意 (i>=0,j>=0) )
例3: 《训练指南》上的某个例题的一个步骤。 要求被覆盖两次的边尽量多, 每条边只可能被覆盖一次或两次。这道题的一个关键步骤就是将这个要求转化为要求被覆盖一次的边尽量少
例4: [AH2017/HNOI2017]抛硬币。 这道题的一个关键步骤就是在状态空间里进行对应。
小结: 写不出了……
updated at 2020.10.31 15:46 例5: AGC020C。 没啥好说的。