DP练习

做题。太菜了只会一些水的qwq。

1. P5020 [NOIP2018 提高组] 货币系统

link

就是从给的一组基里面去掉几个,使得剩下的线性无关。

直接完全背包跑一遍,如果一个数能被多于一种方案表示出来(除了自己表示自己),那么就可以去掉。

O(Tnmaxai),勉强过。

2. P1131 [ZJOI2007] 时态同步

link

不像DP。

先跑一遍算每个终止结点的时间。然后观察到给一个结点与父亲的连边+1会使得整个子树内的终止结点时间+1。显然为了最小化,一个子树内的所有终止结点最后都变成其中的最大值。

于是就处理出每个子树内的最大值,然后计算当前根节点统一时态到最大值的代价。DFS一遍统计就行。O(n)

3. P3572 [POI2014] PTA-Little Bird

link

定义fi为到第i棵树的最小疲劳值。

容易写出转移fi=minikji1fj+[didj]

比一般的单调队列优化的形式多了个艾弗森括号。但其实问题不大,因为括号前系数为1。分析一下,如果把f都塞到单调队列中,取出最小值会如何:

  • 艾弗森括号为0,此时一定为最小。

  • 艾弗森括号为1,此时可能比f相同的大1,不大于次大值。

于是f相同的保留d较大的即可。O(n)

4. P5322 [BJOI2019] 排兵布阵

link

将每一列视作一个泛化物品,给第i列分配k个人的贡献wi,k可以O((s+m)n)预处理。

定义fn,m表示给前n列分配m个人的答案。注意到给一列分配的人一定恰好比这一列中的某个数的两倍大一,否则不优。

于是容易写出转移fn,m=mink为第n列某个数fi1,m2k1+wi,2k+1

O(nms)

5. P3174 [HAOI2009] 毛毛虫

link

找最大毛毛虫。

考虑从一个点开始往下找,钦定当前点不能往周围拓展一条边的最大毛毛虫fu。这样答案就是枚举每个点,再枚举每个儿子,将最大和次大合并即可。

细节比较多,注意当前点实际上可以向父亲拓展,但钦定的时候排除了这个情况。注意可能没有儿子或者只有一个儿子的情况。总之注意细节。O(n)

6. P3188 [HNOI2007] 梦幻岛宝珠

link

超大背包。考虑泛化物品。

注意到wi=a×2b的限制,a,b很小,从这里入手。将每个wi拆成这种形式后,按2b分组。每一组当做一个泛化物品,记gi,j表示第i组在容量为j×2i时的最大价值。这样每个泛化物品的价值函数就求出来了。

W没有这个限制,在对泛化物品做背包时需要再次定义状态:fi,j表示j×2i+W&(2i1)的背包容量时可以得到的最大价值。

我们按物品次序搞这个东西,钦定求fi,j时只考虑前i组(最高位为2i),于是可以写出转移:fi,j=maxk{fi1,2(jk)+(W>>(i1))&1+gi,k}(下面那一大坨是i变化后W&(2i1)也要变,而且分出去了k×2i的容量)。特别地,在边界i=0时,f0,j=g0,j

于是做完了,复杂度懒得分析,O(能过)

感觉这种就是要找点性质让超大的物品可以用一种状态高效表示出来。

7. P2519 [HAOI2011] problem a

link

首先可以将给出的限制转化成一段区间内的人的分数相同,可以发现合法的方案是选择一些不相交区间。

然后发现要求最少说假话的人,这里面有些区间不存在,一定是假话。

可以考虑补集转化,来求最多说真话的人,那么就不用考虑上面的东西。

发现对于一段区间,说真话的人数为min(提到这段区间的人数,这段区间的长度)

那么将上面那坨东西视作区间的权值,那么问题就是选出一些不相交区间使得权值和最大,答案为n最大权值和

于是有朴素DP,首先按r从小到大排序,设fi表示考虑到前i个区间的最大权值和。有fi=max0j<i,rj<lifj+wi

这里已经可以二分出最大的j然后前缀max搞一下就行。还有一种只需维护前缀max的做法,将DP过程放到坐标轴上,fi表示考虑到坐标轴上i位置能获得的最大权值和。有fri=max0j<i,rj<lifrj+wi,这样后面那一坨max[1,li]中的f相比于原来的形式空出来了很多为0的位置,可以发现f本身做一遍前缀max对答案是没有影响的,于是可以按r从小到大依次DP,每到一个新r就先做一下f的前缀max,转移时就直接fri=max{fri,fli1+wi}

瓶颈在于排序,O(nlogn)

8. P6564 [POI2007] 堆积木KLO

link

首先状态很妙。一开始可以想到朴素的二维状态,有很多种定义方式,最后都指向了同一种方程,形如fi,j=max{fi1,j,fi1,j1+[ai=j]}

把艾弗森括号先不管,放到二维平面上转化为平行四边形中最值,再拉伸一下平面就转化为二维前缀最值,然后加上艾弗森括号就上扫描线或者树套树解决。

更为妙的状态还是一维的,定义fi表示第i个在贡献序列中且有贡献的最大贡献和,那么转移就是fi=(maxj<i,ai>aj,aiajijfj+1)[iai]

这个转移的限制是个三维偏序,不太好,但是观察一下,发现当aiajijai>aj时,一定有i>j。所以这就是二维偏序。

整理一下式子,限制就是iaijajai>aj,这也规定了转移顺序,于是把二元组(iai,ai)扔到二维平面上,再排个序,套上树状数组求最值就行。注意iai<0的点的贡献总是0,要判掉。

O(nlogn)

9. P3205 [HNOI2010] 合唱队

link

发现每次插入一个人只会在头和尾插,然后考虑从终态推回来,可以自然想到要知道当前最后一个人是在头还是在尾。于是记到状态里。这种在首尾每次增减一处的题型是经典的区间DP的样子。

设状态f0/1,l,r表示对于最终队形中的[l,r],最后一个人在首/尾,有多少种可能的初始队形。

答案就是对于最终队形中的[1,n],最后一个人在首尾两种情况的方案数之和。

如何转移?大力分讨,去掉最后一个人后,讨论倒数第二个人在剩下队形的首/尾,相加即可。

这样区间DP是O(n2)的。

10. P2606 [ZJOI2010] 排列计数

link

神奇转化。

首先将限制反过来,pi<p2ipi<p2i+1。那么这就是一个小根堆。

在一个小根堆中,根节点肯定确定了是最小的一个数。这道题中小根堆的结构也是确定的,那么左右子树的大小也是确定的。设当前子树中一共要放n个互不相同的数,左儿子的子树大小为szlsfu表示将uszu个互不相同的数填满的方案数。

那么方程是很简单的:fu=(n1szls)×fls×frs

然后DFS一遍就做完了。

11. P4310 绝世好题

link

看到二进制,想到拆位。限制可以转化为二进制下同为1的位数不少于1位。

定义fi表示以第i个数结尾的序列的最长长度,那么转移就是fi=maxaj满足限制fj+1。显然对于限制我们只需关心ai1的那些二进制位。而这些位上,满足限制的aj也一定是1,这是充要的。

那么可以考虑维护第i位上为1的位置的f的最大值mxi,那么fi=maxaij位为1mxj+1。这里的mx中有些位置在重复贡献,但由于max,对答案没有影响。

O(nlogV)

12. P1282 多米诺骨牌

link

首先来说自己的做法。首先考虑求出所有能得到的上方数值的和,那么直接扫一遍就能得到最小的差值。为求这个最小的差值,首先原样不动,得到初始数值,然后一次旋转可以造成一定贡献,一个贡献只能得到一次,于是做背包就可以得到所有可以得到的和。接着发现要求的是最小旋转次数,那么可以记下在取得最小差值时上方数值之和,注意有两个值,即xsumx,再做一遍背包记录得到这个数的最小旋转次数即可。是O(n2)的。

更为简单的做法是,定义fi,j表示考虑前i个,下面的上面的=j时的最小旋转次数,然后转移是简单的。第二维可能为负数,于是加上一个平移量即可。第一维可以滚动。很优秀。也是O(n2)的。

13. P2943 [USACO09MAR] Cleaning Up G

link

很牛的东西。

朴素DP是简单的:fi=min0<j<ifj+(j+1到i中不同数字个数)2

首先分析答案上界,发现答案不超过n,因为总是可以每个单独分一段。然后看贡献中的形式为k2,于是可以知道kn。于是对于每个i,转移的位置只需考虑n个位置Lj,满足[Lj,i]中一共有j个不同的数。可以用桶动态维护L

然后就有fi=minjfLj1+j2O(nn)

14. P5785 [SDOI2012] 任务安排

link

费用提前计算的思想。

定义fi表示处理前i个的最小代价,然后发现每次开机会对后面造成影响。于是修改定义为处理前i个并且考虑对后面的影响后最小代价。

朴素DP式子:fi=min{fj+sumti(sumcisumcj)+s(sumcnsumcj)},然后斜率优化。注意斜率不单调,横坐标单调。用二分。

O(nlogn)

15. P2051 [AHOI2009] 中国象棋

link

状态比较妙。

首先棋盘上DP,考虑以行为阶段。尝试在当前这一行中填入炮,由于至多填两个,转移是O(1)的。

但是发现往这一行中填的炮受到以前填过的炮所在列的影响,于是在状态中记录还有多少个可用的列。

定义状态fi,j,k表示考虑到第i行,这一行上方的列中有j列上有1个炮,有k列上没有炮。于是转移很自然。

O(nm2)

16. P2396 yyy loves Maths VII

link

卡常题。

状压不是难点。发现要算每种二进制状态对应的数值,但是如果把这部分单独来算就因常数过大寄了。

技巧是递推这个值,每次把状态的lowbit位取出来,然后vali=valip+valp

17. P3349 [ZJOI2016] 小星星

link

容斥计数,子集反演,状压。

首先看到是把一棵树放到一张图上,点数很少,先上树上状压DP。定义fu,p,S表示在u这棵子树内,u对应图上的p,用S中的点来对应u这棵子树的方案数。可以转移,但是发现这样转移很麻烦,状态数感觉也很大,时间复杂度O(n33n)更是爆了。

发现S的大小肯定为u子树的大小,u对应的所有状态是可以预处理的(好吧没什么用,或许可以让暴力冲过去,这一条是状压优化的常用手段)。

S的限制让我们很难受,考虑去掉它,想到了容斥(容斥就是拿来去掉限制降一点复杂度,虽然要另外算一个式子,但是这两个部分可以平衡一下,让总复杂度是降的)。把S的限制去掉后,对于不同的S,在树上的计数是相互独立的,在DP前枚举一下S就行。现在u子树内的对应的编号是可以重复的,只需记fu,p表示在u这棵子树内,u对应图上的p时,方案数。

转移是简单的:fu,p=vsonu(qS,(p,q)Efv,q),其中pS,初始化p,fu,p=1

开始容斥,现在我们可以得到用S去对应整棵树的方案数fS=pf1,p(这里默认以1作为树根)。可以发现S表示对应整棵树所用的编号构成的集合至多S。设对应整棵树所用的编号构成的集合为T,用T恰好对应整棵树的方案数为gT,那么有fS=TSgT

使用子集反演的力量,gS=TS(1)|S||T|fT,取S=U即可得到答案。O(n32n)

18. P1291 [SHOI2002] 百事世界杯之旅

link

简单题,但是我的□□更胜一筹。

定义fk表示得到k个的期望步数。于是考虑从kk+1的增量,有i0(kn)inkn(i+1)=nnk。然后就完了。神秘输出格式模拟一下就好。

19. P2193 HXY和序列

link

序列计数,典and水。

fi,x表示考虑前i个位置,第i个位置上放x的方案数。

转移是简单的,fi+1,kxfi,x

可以滚掉第一维。记得及时清空

O(nx1nx)=O(n2lnn)

有数学做法,没推。

20. P2467 [SDOI2010] 地精部落

link

排列计数,规约(或者排列里特殊的“离散化”)。

套路起手,定义fi,j,0/1表示考虑前i个位置,用1i的排列去填,最后一个位置填j,且j比前一个数更小/更大的方案数。

如何转移?考虑去掉最后的j,那么前面位置[1,i1]上填的就是1i的排列去掉j。这个东西和f的定义很不兼容,考虑转化一下。

考虑把前面的数离散化(即>j的数都1),不改变大小关系,那么原来和现在符合条件的序列是一一对应的。

此刻[1,i1]上填的就是1i1的排列(注意离散化后j+1j之类的,在转移中是边界),考虑用上f,可以得到转移:

fi,j,0=jk<ifi1,k,1fi,j,1=1k<jfi1,k,0

发现转移是前缀后缀和的形式,直接优化。并且第一维可以压掉。O(n2)

21. P2401 不等数列

link

欧拉数板子,但是O(n2)

fi,j表示长度为i的排列,有j个位置是前小于后的。考虑i+1加入1i的排列中。i+1插入到j个前小于后和第一个数前面空中时,不产生新贡献,系数是j+1。另一种同理。

posted @   RandomShuffle  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示