集训游记 7.15-7.17 基础算法/动态规划

Day1

LOJ#6490. 「XXOI 2018」暑假时在做什么?有没有空?可以来学物理吗?

考虑 CDQ 分治.设当前分治区间为 [l,r]mid=lr.考虑跨 mid 区间的贡献.
先更新 [mid+1,r] 中的点的答案.枚举区间右端点,左端点在 [l,mid] 中的部分形成一个区间.做一个前缀和后可以转化为区间 RMQ 问题.然后区间 [l,mid] 中的点的答案同理.枚举区间左端点,然后右端点在 [mid+1,r] 中的部分形成一个区间.

Buy Low Sell High

反悔贪心.对于某一天 i,假设在这天卖出一只股票,肯定要在前面的某一天买进一只股票.假设买进天为 j,则利润为 PiPj.按天数顺序扫描,用小根堆维护之前每天股票的价格.若选择当前天卖出股票,肯定优先选择股票价格最小的天数.加入反悔机制:若当前天选择了卖出股票,将 PiPj 放入小根堆.

P5290 [十二省联考 2019] 春节十二响

7.15Test T4

考虑构造 p 进制线性基.由于 p 是质数,故任意一个非 0 的数在模 p 意义下的 k 倍可以张成剩余系中的所有数.故我们将所有数按行依次写开构造矩阵.将前面的位数保留成为自由元.然后贪心地使它们最大即可.

具体地,考虑插入一个数.跟异或线性基相同的,从高位开始枚举,若碰到不存在数字,并且自己哪一位非 0 的位数,将自己插入到线性基的那一位.否则将它的那一位消成 0

Day2

主要讲的是 DP.然后题补的不多.简单地记一下.

然后相对来说比较简单的题目就记一下大体思路.难题还是尽量给出实现.

做题记录以例题为主,之后会去补作业.

序列 DP

序列 DP 的题目.由于序列的拓扑结构相对简单,所以题目本身往往相对诡异.写题时容易无法下手.需要斟酌状态设计、转移顺序和优化方式.有时可以思考重排序列使得有贡献的转移集中在某一区间.

P7154 [USACO20DEC] Sleeping Cows P

由于保证了奶牛和牛棚大小互不相同,我们可以考虑把奶牛和牛棚放在一起排序:每个元素只能和前面的元素匹配,这个性质是有利于设计 DP 状态的.

先不考虑极大匹配的限制.记 Fi,j 表示前 i 个元素有 j 个奶牛未匹配(待匹配).按奶牛和牛棚分类转移即可.

再来考虑极大匹配的限制.那么每个奶牛就有两种选择:

  • 选择匹配,需要等待后面的某一个牛棚.
  • 选择不匹配,不允许后面有闲置的牛棚.

虽然一个奶牛选择是否匹配影响了后面的牛棚的抉择状态.但我们不妨在遍历到奶牛的时候就 提前决定 其是否选择匹配.为防止后效性,肯定是需要重新设计 DP 数组的.

Fi,j,0/1 表示前 i 个元素,有 j待匹配的 奶牛,是否存在选择不匹配的奶牛.这样的好处是遍历到牛棚时,容易检查出对于一种状态,它是否 必须和前面的某一个待匹配奶牛匹配

有转移方程:

i 是牛棚:

Fi1,j,0Fi,j,0Fi1,j,0Fi,j1,0Fi1,j,1Fi,j1,1(j>0)

i 是奶牛:

Fi1,j,0Fi,j+1,0Fi1,j,0Fi,j,1Fi1,j,1Fi,j,1Fi1,j,1Fi,j+1,1

P8863 「KDOI-03」构造数组

操作次数显然是固定的 m=bi2
那么我们将每个操作时的数组看成一列,会形成一个大小为 n×m 的网格.然后每一列可以选择两个点 +1.要求每一行恰有 bi+1 的方案数.

设计 DP 状态,记 fi,j 表示前 i 行有 j 列已经添入了两个 +1.这样的好处就是添入一个 +1 和没有添入的列数都可以算出来.

转移枚举当前行有多少个 +1 填在了之前有一个 +1 的列上即可.
有转移方程:

fi1,j(mi1,1k)(mi1,0bi1k)fi,j+k

其中 mi1,1,mi1,0 分别表示前 i1 行选择了 j 个有两个 +1 的列,剩下的中有一个 +1 和没有的列的个数.

CF1363F Rotating Substrings

非常神仙的线性 DP.循环位移一位很丑,我们可以想成:把某一位的字符扔到序列的前面某一位去.就有一种特别神奇的,从后往前 DP 的方法.

Fi,j 表示考虑 S 的后缀 i 通过将后缀中的字符扔到后缀中,或者挂起后缀中的某些字符,最终达到和 T 的后缀 j 匹配的最小挂起字符个数是多少.

这里 “挂起” 的意思是将某字符拎起来,但还不决定把它扔到哪.

Tj 的匹配方式分类可以得到:

  • SiTj 匹配,有

Fi+1,j+1Fi,j

  • Si 挂起,让后面的 S 匹配,有

Fi+1,j+1Fi,j

  • Si 去匹配后面的 T,把后面 S 中挂起的等于 Tj 的字符扔到这里来和 Tj 匹配.

Fi,j+1Fi,j

这时要有 S 的后缀 iTj 字符的数量大于等于 Tj 字符的数量.

CF1188C Array Beauty

a 数组排好序.

发现 min(|bibj|)=x 的子序列数量是难求的,但 min(|bibj|)x 的子序列数量容易求出的.记 numx=min(|bibj|)x.有

ans=xnumxnumx1

这是我们已经可以做了.但其实它有更美观的形式.设 numx=min(|bibj|)=x

ans=xx×numx=xixnumx=ixinumx=inumi

P7985 [USACO21DEC] Paired Up P

存在性质:交叉匹配一定不更优于不交叉的匹配.因为这样可以减小两对匹配的距离绝对值.或者这样说:若存在若干对匹配相交,肯定有一种合法的调整方案使得它们不相交.

考虑 T=1.最小化是不需要考虑极大匹配限制的.因为一组非极大匹配肯定不能成为最优解:将其变成极大匹配答案肯定更小.我们可以记 Fi,j 表示前 i 头荷斯坦牛和前 j 头更赛牛的答案.有转移:

Fi1,j1Fi,j(i,j)Fi1,j+costiFi,jFi,j1+costjFi,j

再考虑 T=2.这个就稍微有点麻烦了.将一头牛变成未匹配的时候,要保证它和前面未匹配的牛不能形成匹配.于是考虑改变状态.
Fi,j,0/1 表示处理完前 i 头荷斯坦牛,前 j 头更赛牛,然后下一头 荷斯坦牛/更赛牛 可以计入贡献的答案.

尝试理解一下这个抽象的状态:就是说下一头 荷斯坦牛/更赛牛 和前面的所有 更赛牛/荷斯坦牛 全部无法匹配.转移时分类讨论:

  1. 保留待贡献的牛的种类.

Fi,j,0+costi+1Fi+1,j,0Fi,j,1+costj+1Fi,j+1,1Fi,j,0/1Fi+1,j+1,0/1(i,j)

  1. 尝试改变待贡献的牛的种类.

Fi,j,0Fi+len,j+len,1Fi,j,1Fi+len,j+len,0

每次找出某一头 荷斯坦奶牛/更赛牛 位置之后的,第一头不能与它匹配的 更赛牛/荷斯坦牛 的 前一个位置,并尝试转移到它那里来.

树形 DP

有点遗憾没讲到换根 DP,反倒是图论讲缩点的时候谈了一下.

CF1778F Maximizing Root

首先有结论,自底而上操作的顺序肯定更优.这符合我们自底而上的 DP 顺序.

最大化 a1,其实是最大化 a1 最终乘上的倍数.如果可以乘上倍数 d,必须满足 da1 子树的因数.正常的想法,应该设计状态考察耗费一定代价能获得的最优因数.但发现子树中最大的因数,从全局来考察不一定在最优.那么我们必须把每一个因数都纳入考量.使用一个改变状态的小技巧:把 DP 的答案纳入 DP 状态中,DP 答案的最小花费,而不是某一花费上的最优答案.而花费的优劣是容易抉择的.

具体地,我们设 Fu,i 表示满足 u 子树存在公因数 i,子树中需要操作的最小次数.

对于不操作 u 的情况,Fu,i 是将子树的 Fv,i 逐点相加.对于操作 u 的情况,即 Fu,i+1Fu,ii

考虑缩小状态数,发现使 a1 可以进行操作,必须使得子树存在因数是 a1 的因数.而 a1 的因数在 1e5 的范围内至多只有 128 个.

P8352 [SDOI/SXOI2022] 小 N 的独立集

相当于在树上最大独立集的外壳假象下的计数.容易想到状态 Fu,i,j 表示 u 子树,勒令 au 不选和勒令 au 选的答案.转移时考虑添加一颗新子树.

这时有技巧 DP 套 DP!就是说状态合并时,转移的新状态需要由原来状态通过某些决策 DP 出来.考察 Fu,i,j,Fv,i,j 合并.指向的状态为 Fu,max(i+i,i+j),j+j

非常优美非常和谐!状态数爆炸!

继续寻找性质:发现勒令不选的答案不会比勒令选的答案小很多.事实上,勒令选的答案去掉 au,就是一种合法的勒令不选的答案.我们新设计一种树上最大独立集的 DP 状态:Gu,0 表示子树 u 勒令不选 u 的答案,Gu,1 表示子树 u 不管是否选择 u 的答案.有 Gu,0[Gu,1au,Gu,1].我们只需要记录一个值,和两个值的差即可!

再来简要分析一下树上背包的时间复杂度:

for(int v:e[u]){
    dfs(v, u);
    for(int i=1; i<=sz[u]; i++){
        for(int j=1; j<=sz[v]; j++){
            ...
        }
    }
    sz[u]+=sz[v];
}

考虑一份这样的树上背包,其实在实现一个这样的过程:
枚举子树 v 和之前子树的贡献,将子树 v 并入之前的子树.两层循环实际在枚举 lcau 处的点对.每次枚举的 i,j 可以一一对应到树上的点对上,故总时间复杂度为 O(n2)

而对于此题,由于还要枚举额外的增量数组.综时间复杂度为 O(n2m4)

Swap and Maximum Block

\red

根据序列建出 trie 树.

发现交换每两个相邻的 2k 区间等价于在 trie 树上交换所有子树宽度为 2k+1 的节点的两个儿子.

对于 k 级子树 u,其子树的最大深度为 nk.子树内每层是否交换的数量总和为 2nk.而 k 级子树一共约有 2k 个.故 k 级的总状态数为 2k×2nk=2n.所以 n 层的状态一共有 n2n 种.

状态压缩 DP

有一道 Codeforce 训练场的题,但主要是乱用 bitset 瞎搞.有时间去补一下.

P7142 [THUPC2021 初赛] 密集子图

主要难在刻画最短路.我们把原图最短路小于等于 i 的部分,集合 S 划分成两部分:最短路等于 i 的部分 S1 和 小于 i 的部分 SS1.考虑加入最短路为 i+1 的部分 S.发现对于 uv(uSS1,vS),连边必须为白色.对于 uv(uS1,vS),连边对于每一个 v 至少存在一个为黑色.然后就可以转移了.

Fi,S1,S2 表示考虑了所有最短路 i 的点,其点集为 S1,其中最短路恰好为 i 的点集为 S2,发生这种情况的概率.

存在转移

Fi,S1,S2×P(S1S2S)×P(S2S)Fi+1,S1S,S(S2S1,S2\empty)

然后我们预处理 P,P 即可.

P7519 [省选联考 2021 A/B 卷] 滚榜

又是一道代价提前计算的好题!
发现让我计算可能排列的个数:一种排列只能算作一次.

考虑状压队伍的集合,然后按揭榜的顺序 DP 是较容易的.由于 b 的取值不确定又影响答案,必须要计入 DP 的考量范围,我们考虑对于任意一种排列对应到唯一的一种 b 的数列上,这样就能保证不算重.

但同时不能漏掉可能的排列:要保证任意一种可能合法点排列在我们的映射方案上都是合法的!

贪心.顺序考虑揭榜的每一个队伍,在保证其能达到当前榜首的前提下,确保其 b 尽量小.这样的构造方法就完美符合了我们的要求.

区间 DP

P4563 [JXOI2018] 守卫

突破口非常奇怪.但又很合理.

考虑一个性质:守卫只能向左边看.那么对于一个区间 [l,r],要使得在这个区间中放置守卫使得所有地方被看见,区间的右端点 r 一定需要放置守卫.那么设 r 在区间中能看见的最左的地方为 p.可以证明:i[p,r],不存在一个地方 j[l,p1],使得 i 可以看到 j.具体来说,在 (p,r) 之中的点一定存在于 p,r 连线的下方.若某一点可以看到 p 左边的点,那么 r 一定也能看到.如果画一张图就会非常清楚.

那么这个区间就被我们划分成了两部分:[l,p1],[p,r].这两个部分互相没有关联.设 Fl,r 表示看守 l,r 需要的最多人数.那么我们就有了转移:

Fl,p1+Fp,rFl,rFl,p+Fp,rFl,r

还有一个细节.那就是当 p=l 的时候,这个转移就不成立了.那我们再考虑第二靠左的,能被 r 看见的地方即可.

CF1178F2 Long Colorful Strip

这个区间 DP 思路还比较自然.

首先想到可以离散化.一次划分顶多产生两个颜色不同的分解点.如果离散化之后的数组长度 >2n,可以直接判断无解.

考虑设计 DP 状态.设 Fl,r 表示把区间 [l,r] 按颜色顺序覆盖完的方案数有多少种.

转移时可以确定最小颜色围出的区间肯定要覆盖最小颜色.然后我们枚举覆盖的区间向左右延伸多少即可.这样会存在许多非法的状态.设最小颜色围出的区间是 [l,r].考虑存在另一种颜色在 l 的左边出现并且在 r 的右边出现之类的情况,其实是无解的.那我们可以做一个这样的特判:当最小的颜色在数组中的出现位置不完全包含于当前的区间中,我们认为当前区间无解.这样就能规避掉非法的状态了.

P9129 [USACO23FEB] Piling Papers G

另辟蹊径的数位 DP.

首先答案是可差分的.那么求坐落于 [A,B] 之间的答案就相当于求 B 的答案减去 A1 的答案.那么我们考虑如何求出形如 T 答案.

像常规方式一样记录 Fi,0/1/2 表示考虑已经填入的低 i 位和 T 的比较结果是 小于/等于/大于.那么当实现转移 ai+xx 的时候比较结果是容易更新的,但实现转移 x+aix 的时候由于前面确定的位数都要向更高位挪动一格,比较的结果就不能确定了.所以这个状态是不可取的.

同样是 提前计算/提前确定 的思想,我们设 Fl,r,0/1/2 表示填入了在 [l,r] 中的位数,和 T[l,r] 中比较的结果为 小于/等于/大于 的状态数.那么向左添一个就相当于 l1,向右填一个就相当于 r+1.同时大小的比较也是很容易确定的.注意到 q 的数量级是 O(n2).我们预处理出所有区间的答案,然后 O(1) 回答即可.

其它 DP 题目

P7967 [COCI2021-2022#2] Magneti

抱き寄せて欲しい 確かめて欲しい
想要被拥入你怀中 想要确认心意

間違いなど無いんだと 思わせて
让我知道 没有误会了什麼

首先按 r 从小到大排序.那么新添加一个磁石只需要考虑不吸引别的磁石即可.

设计状态就需要一些奇思妙想.设 Fi,c,l 表示考虑前 i 个磁石,形成 c 个联通块,耗费的总长度为 l 的方案数.

然后考虑添加一块磁石可能的三种变化:

  1. 独立为一个联通块:

Fi,c,lFi+1,c+1,l+1

  1. 和其中的某一联通块合并:

Fi,c,l×2nFi+1,c+1,l+ri+1

  1. 和其中两个联通块串起来:

Fi,c,l×2(c2)Fi+1,c1,l+2ri+1

那么最后答案肯定是 iFn,1,i

posted @   ckain  阅读(117)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示