中高等DP总结(更新中

1.CF613D Kingdom and its Cities

题意:给定一棵树,每个询问给出一些关键点,要求删掉最少的点使这些点两两不联通,无解输出-1。

思路:先判无解:只要有一个关键点的父亲也是关键点就无解。因为会被删除的点肯定是这些点中一些点的lca,所以考虑建虚树,然后树形DP。具体来讲,设gx表示当前有没有关键点与x直接联通(若x为关键点则gx=1),fx表示点x的答案。转移时先fx=yson(x)fy,然后根据x是否是关键点与yson(x)gy的值(设为sum)分类讨论:

1.gx=0
如果sum>1那就将点x删去,fx++
如果sum=1那就将gx=1
如果sum=0自然不变

2.gx=1那与x联通的点都得删,fx+=sum

最后f1就是答案,复杂度n×log(n)

2.P2519 [HAOI2011]problem a

题意:一次考试共有n个人参加,可能出现多个人成绩相同的情况。第i个人说:“有ai个人成绩比我高,bi个人成绩比我低。”请求出最少有几个人没有说真话。(其实这就是原题面,这么简洁那我不直接复制过来)

思路:(十分人类智慧,不知道是怎么想出来的)首先定义一个人的排名是严格高于他的人数加1,然后就可以把每个限制改成:“我是第ai+1名,算上自己共有naibi个人与我同分”,然后变成区间[ai+1,nbi]表示与第i个人分数相同的区间,并把这个区间的权值定义为区间长度与所有aj=ai+1j=nbij的个数的较小值。然后我们就把问题转化成了要选出若干不交的区间,最大化权值和。

我们发现,对fi做贡献的j要满足rj<li,因此将所有区间按r排序后j就是一个前缀的形式,转移时二分出最大的j,再维护一个前缀最大值即可完成转移。复杂度nlog(n)

3.P6047 丝之割

题意:有若干条形如(u,v)的弦,可以进行若干次操作,每次操作选定(i,j),会切断所有满足u>i,j<v的弦会被破坏,代价为ai×bj,求破坏所有弦的最小代价。

思路:斜优裸题(只可惜第一步没想出来)先考虑那些弦不会做贡献,很容易发现如果有两个弦i,j满足uj>ui,vj<vi那么如果要删弦i就一定会同时删弦j,那么弦j就不做贡献。当我们把所有不做贡献的弦j删去后,就不会存在一条弦的u大于另一条弦的uv较小,换而言之就是弦的u,v都是单增的有了这个性质就很好DP了。

fi为破环前i个弦的最小代价,转移方程为fi=minj=1i1(fj+mink=1uj1ak×mink=vi+1nbk)
朴素的转移是O(n2)的,我们考虑优化转移。我们发现,这个转移的形式似乎可以斜率优化,把fj当成y,把mink=1uj1ak当成x,把mink=vi+1nbk当成k,就和斜优的形式一模一样了,就可以愉快的套板子了。复杂度O(n)

4.P6564 [POI2007] 堆积木KLO

题意:给定序列a,可以任意删除一些数,删除后后面的位置会向前补齐,求最后序列中最多有多少个数满足ai=i

思路:我们记fi表示钦定最后i在自己位置上时i前最多有多少个满足条件的数,然后可得:fi=max(fj|j<i,aj<ai,aiajij)+1。朴素转移是O(n2)的,我们尝试把合法的j变成一个前缀的形式。由aiajij可以推出jajiai,因此先排除不合法(即ai>i)的数,再按iai排序后DP,然后用树状数组维护最大值即可。复杂度O(nlog(n))

5.P4099 [HEOI2013]SAO

题意:给定一颗树,遍历方向为根到叶子或叶子到根,求遍历方案数。

思路:看到求拓扑序方案数首先想到设f[i][j]表示ii的子树里拓扑序排名为j的方案数,然后考虑合并时如何转移。f[x][k]=i+j=kf[x][i]×f[y][j]×Ck1i1×Csiz[u]+siz[v]ksiz[u]i,这个转移是O(n3)的,但是我们发现这个组合数与f[y][j]无关,也就是说可以用前缀和优化转移,这样复杂度就是O(n2)的了。注意转移时根据遍历方向j的范围会不一样,需简单分个类。

6.P3160 [CQOI2012]局部极小值

题意:往n×m的棋盘上填入1~n×m,每个数只能填一次。告诉所有是与其八联通的格子里最小的数的位置,求填数的方案数。

思路:因为所有格子里的数互不相同,所以在4×7的棋盘上最多有8个这样的位置(即为局部极小值),这个数据范围提醒我们可以状压。又因为我们要填入数字,我们设DP状态为f[i][S]表示已经填了1 ~ i1,当前要填i,填完i后局部最小值的状态为S,转移的时候我们分两种情况。一种是当前的数填到某给局部最小值的位置,这时直接枚举那个地方还没填数即可。第二种是填到一个不是最小值的位置,因为我们是从小到大填数的,所以局部最小值一定得在周围的数填入之前填入,这样就很方便预处理出每种状态下有多少点可以被填。但我们发现题目中说的是“所有”,这就意味这我们随便填会把一些不是局部最小值的位置变成局部最小值,这是只需大力容斥就行了(反正最多也只能填8个数),用一个不多的方案减去多1个的方案,加上多两个的……就行了。复杂度嘛,反正不高(主要是懒得算)。

7.P3600 随机数生成器

题意:给一个序列a,a中每个数是在[1,x]中的随机数,然后给定q个询问minj=liriaj,求q个询问的最大值的期望。

思路:(不愧是黑题)首先,如果一个区间完全包含了另一个区间,那它的最小值一定不大于它包含的区间的最小值,那么它就不做贡献。如果直接求期望没什么好方法,我们考虑把它转化为一个计数问题,最后除以xn就是答案。设hi为最终答案i的方案数,然后最终答案为i的方案数就是hihi1,这等价与每个区间的最小值都i,即每个区间都存在i的数,我们设gj表示在[1,n]内选出j个点,是的每个区间都被覆盖的方案数,然后hi就等于gj×ij×(xi)nj。然后考虑用DP算出gj。我们设f[i][j]表示前i给位置放了j个点,且第i个位置必须放点,覆盖了所有左端点i的区间的方案数。先预处理出fl[i]fr[i]分别表示覆盖了i的最左/右的区间,如果没有就是左侧最接近它的区间。因此f[i][j]=fr[k]+1>=fl[i]f[k][j1],容易发现k处在一个区间内,因此可以前缀和优化。然后就得到gj=fr[i]=qf[i][j],然后也可以算出hi。复杂度O(n2)

8.CF79D Password

题意:有长度为n的01串和l个长度,每次可以将某个长度的子区间的取反,初始全是0,求把给定的k给位置变成1的最小步数。

思路:(把状压和最短路结合起来的题目好像很罕见)看到k10就想到是状压,但是区间取反不好维护,我们考虑差分,即每个数异或上前一个数,那区间取反可以变成两个单点取反。因为只有k个点最后为1,所以也最多只会有2k个数最后差分数组为1。设f[S]为把01串变成状态S的最小步数,因此f[S]+cost(i,j)f[S|(1<<i)|(1<<j)]其中cost(i,j)表示只把i,j取反要花费的最小代价。我们考虑每进行一次操作是把相隔为ai的两个位置取反,而我们取反l,r再取反r,l,就相当与对l,l进行了取反,然后我们发现这很像一个最短路问题,每个点向x+aixai连距离为1的边,再用bfs求一遍最短路即可求出cost(i,j)。总复杂度O(nm+22k)

9.CF662C Binary Table

题意:有一个n×m的0/1表格,可以任意将一行或一列的0/1翻转,求最终最少有多少个1。

思路:我们发现n只有20,就想到了状压DP。对于行的不同翻转状态只有2n种,我们自然想到了设dp[S]表示行的翻转状态为S时的答案。设每一列的状态为ai,再设辅助数组f[i]表示列状态为i时翻转后最少有多少个1,即min(ppc[i],nppc[i]),那么dp[S]=i=1mf[Sai]。但这样的复杂度是O(m2n)的,明显过不了,我们考虑如何优化。我们考虑枚举答案y=Sai,那么 dp[S]=i=1my=02n1[y==aiS]f[y],但前面的i=1m还没丢掉。我们设Q[i]表示有多少列的状态为i,那么dp[S]=i=02n1y=02n1[iy==S]Q[i]×f[y],换个写法就是dp[S]=iy=SQ[i]×f[y],这个形式是不是跟FWT长得一模一样?然后就可以愉快的套板子了。复杂度O(nlog(n))

10.CF1428G2 Lucky Numbers (Hard Version)

题意:定义一个数的权值为:若第i位(个位算第0位)为3的倍数,则产生x3×ai的贡献,多次询问一个数被拆成k个数产生的总贡献最大值。

思路:(什么神必多重背包+分组背包) 首先发现一个数位上是3还是6还是9是没有影响的,所以可以把6和9当成3来处理(减小思维难度及码量)。接着我们发现可以把这k个数中的k1个每一位都是3的倍数,然后考虑剩下的一个有数位不做贡献的数。先考虑这k1个数,我们把分成k1个数之和反过来看,即由这k1个数组成当前数,再把每一个数位拆开,发现这可以当作一个多重背包,第i个物品的价值为ai,体积为10i,有3×(k1)个,但因为k很大,所以采用二进制分组优化。再考虑剩下的一个数,就简单的当作一个分组背包来做,不过要注意这时也有可能还有3的倍数的数位。复杂度O(nlog(k)+(60?)n)(还可以顺带把Easy Version写了,双倍经验)

11.CF1393E2 Twilight and Ancient Scroll (harder version)

题意:n个字符串,每个字符串可以删掉一个或者不删,问有多少种方案是得字典序不降。

思路:(这题明明就是考串串科技)首先可以想到一个朴素的|S|3的DP,设f[i][j]为第i个串删第j个字符使得这东西字典序不降的方案数,若不删则j=len+1。然后考虑优化转移。首先想到,可以把字符串想作一个数,比它小的数是一个前缀的形式,那字符串也是一样,因此把字符串删掉一个之后的len个字符串排序后转移就可以用前缀和优化了。但是这样空间显然开不下,时间上也过不去。我们采用贪心的思想,考虑相邻的两位,他们的前缀是相等的,如果这两位相等,那删掉后的字符串也相等,若不相等,就可以比出大小,最后稍稍处理一下删第n+1个字符的情况就可以O(n)了。然后我们考虑不同字符串之间怎么高效比大小,这时就可以用哈希+二分,找到两个串第一个不相等的位置,就可以比大小了,单次O(log|S|),共O(|S|)次,因此总复杂度O(|S|log|S|+|S|)。(又是一道双倍经验的题,好耶

12.CF585F Digits of Number Pi

题目:给定数字串s,x,y(len(x)=len(y),xy),求存在长度不小于len(x)2的子串是s的子串的数字串t[x,y]的数量。

思路:(为了这道题我甚至专门学了半天的SAM)。首先看到[x,y]第一反应肯定是数位DP,但又因为与字符串匹配有关,自然就考虑上AC自动机或SAM,而我写的是SAM的做法。设f[cur][pos][len][lim][flag]表示当前在第cur位,在SAM上为第pos个节点,当前已匹配的字符串长度为lenlim=0/1表示有没有顶到上界,flag=0/1表示目前长度合不合法。转移时枚举下一个选的哪一个数字,若长度已合法或SAM上当前节点有这个儿子则可直接转移,否则不断跳link直到有这个儿子或跳到了1号节点为止,然后再转移。复杂度O(10nd2)。(又一次SAM忘开两倍空间了,警钟敲烂

13.CF1188C Array Beauty

题意:定义一个序列的权值为两个数之差的绝对值的最小值,求长为n的序列a的所有长为k的子序列的权值之和

思路:首先肯定是对a数组排序。我们发现,这一题的值域很小,那做法可能和值域有关。答案的最大值肯定不会超过ank1,因此我们考虑枚举答案v,然后DP计算权值v的方案数,然后直接将方案数相加即可。然后设f[i][j]表示当前在第i个数且选第i个数,已经选了j个且满足条件的方案数,所以f[i][j]=aiakvf[k][j1],然后用前缀和优化就是O(nk)的了。总复杂度O(Vknk)=O(nV)

14.CF1179D Fedor Runs for President

题意:在树上删除一条边后,求最多能形成多少条简单路径。

思路:(感觉这题的难度比前几题上了一个台阶) 大体做法:树上斜率优化。(实在难以理解) 首先只考虑加一条边后会多出来多少条路径。假设加入的边为(x,y),设skpath(x,y)上一点k不向路径延伸的子树大小,那

ans=kpath(x,y)sk(nsk)2

=n×kpath(x,y)skkpath(x,y)sk22

=n2kpath(x,y)sk22

要让答案最大,我们就要选一条路径使kpath(x,y)sk2尽量小。

我们设x为当前点,然后计算每一条经过x的路径的答案。设fxx的子树中让上式最小的路径,则fx=minyson(x)fy+(sizexsizey)2其中sizexsizey即为sx

求出这个后,考虑如何将两条路径合并。先朴素直接枚举两个儿子来转移,即

ans=minu,vson(x),uvfu+fy+(nsizeusizev)2

这样一次转移是O(sonx2)的,但看到这个二次式我们尝试用斜率优化。我们枚举一个u,然后求出最优决策点v。枚举两个点i,j假设ij更优,那么有

fu+fi+(nsizeusizei)2fu+fj+(nsizeusizei)2

化简后可得

fi+sizei22(nsizeu)sizeifj+sizej22(nsizeu)sizej

再变形可得

(fi+sizei2)(fj+sizej2)2(nsizeu)(sizeisizej)

因此当sizei>sizej时,

(fi+sizei2)(fj+sizej2)(sizeisizej)2(nsizeu2)

然后再注意sizei<sizej时不等号变号,以及特判一下等于即可。还有就是我们按size大小先给所有儿子排序一遍后转移就很方便了。

总复杂度O(nlog(n))(感兴趣的话可以自己证一下复杂度,我太懒了这里就不证啦)

upd:其实很好证。

15.CF115D Unambiguous Arithmetic Expression

题意:给一个不含括号的表达式,求有多少种方法给其加上括号使得其仍合法。

思路:(一眼区间DP,只是n2000 不过好像区间DP减减枝可以过,但我没试。设dp[i][j][0/1]表示考虑到第i个位置,前面已经有j个左括号为匹配,当前填的是"("还是")",然后考虑转移,方向是dp[i][j][0/1]dp。先考虑dp[i][j][1],那么有dp[i][j][1]dp[i+1][j+1][0](在后面加一个左括号就是j+1个左括号未匹配),dp[i][j][1]dp[i][j1][1](在自己这里再添一个右括号)。然后是dp[i][j][0],那么有

{dp[i][j][0]dp[i+1][j+1][0]s[i]=+/dp[i][j][0]dp[i+2][j+1][0],dp[i+1][j1][1]s[i]=number

然后这道题就做完了。复杂度O(n2)

16.P3349 [ZJOI2016]小星星

题意:给定有n个点的数和无向图,求有多少种标号方案使得树上每一条边都在无向图中存在。

思路:考虑到求编号,我们设f[i][j][S]表示i子树内,i标号为j,且使用了S中的标号的方案数,但转移时要枚举子集,复杂度是O(n3×3n)的,过不去,我们考虑优化。首先很容易想到把标号集S的限制去掉,但这样会出现重复编号,那容斥不就解决了吗?具体来说,对于每个S(0,2n1)求出每个点的编号都在S内的方案数,然后用|S|=n的方案数减掉|S|=n1的,再加上|S|=n2然后这题就做完了。复杂度O(n3×2n)

17.P2612 [ZJOI2012]波浪

题意:定义一个排列的波动值为相邻两数之差的绝对值之和,求所有长为n的排列波浪值不小于m的概率,保留小数点后k位。

思路:(上古时期模拟赛考过简单版,不出意外获得了0分的好成绩) 看到绝对值不好处理,一个常见的套路是考虑从小到大插入每个数依次计算贡献。我们发现一个数i作的贡献只和前i1个数组成的连续段情况以及和边界的关系有关。我们设dp[i][j][k][l]表示考虑到第i个数,一共组成了j个连续段,总贡献为k,有l个连续段与边界相连。然后考虑转移。

1.i不与任何连续段相连,那么连续段数+1,贡献减少2i,边界情况不变,有j+1l种方案。

2.i一边与边界相连,另一边不与连续段相连,那么连续段数+1,贡献减少i,边界上的l+1,方案数有2l

3.i一边与连续段相连,另一边不与连续段相连,那么连续段数不变,贡献不变,l也不变,有2jl种方案。

4.i一边与边界相连,另一边与连续段相连,那么连续段数不变,贡献+i,边界的l+1,有2l种方案。

5.i两边都与连续段相连,显然连续段数减少1,产生2i的贡献,边界情况不变,有j1种方案。

总复杂度O(n4)

坑点:小数点后30位要用__float128,边转移边除以i,以免除以n!时爆精度,还有要用滚动数组。

18.P4383 [八省联考 2018] 林克卡特树

题意:在树上选出k+1条不相交的链使得链的边权和最大。

思路:WQS二分+树形DP。看到恰好多少条就想到了WQS二分,二分选出一条链的代价,然后用树形DP算出选出多少条链最优。具体的,设dp[i][0/1/2][0/1]表示在i的子树中,点i的度数为0/1/2,最后的0/1表示是权值还是选了几条链。转移时:

dp[i][0]=maxk=02dp[j][k]

dp[i][1]=max(dp[i][0]+dp[j][1]+(wj,0),dp[i][0]+dp[j][0]+(wjmid,1),maxk=02dp[i][1]+dp[j][k])

dp[i][2]=max(dp[i][1]+dp[j][0]+(wj,0),dp[i][1]+dp[j][1]+(wj+mid,1),maxk=02dp[i][2]+dp[j][k])

复杂度:O(nlog(n))

19.P1721 [NOI2016] 国王饮水记

题意:给定一个序列h表示每个城市的水量,保证hi互不相等,可以进行k次操作,每次可以任意指定一些位置并把每个位置变成它们的平均数,求1号城市的最大值(保留p位整数)。

思路:(看完这道题38页的PPT,我整个人都被震撼到了) 首先可以找一大堆性质。比如,比1号城市小的水量肯定没用;合并时一个一个合并比一起合并更优;一个城市最多和1号城市联通一次;每次合并一定包含1号城市;当次数不足以每次都一个一个合并时,一定是将h排序后的连续一段。然后就可以DP了。设f[i][j]表示前i个位置合并了j次的最优值,那么f[i][j]=maxk<if[k][j1]+siskik+1。这样的复杂度是O(n2kp)的,然后发现决策点是单调的,这样就可以斜率优化,复杂度O(nkp),但我们发现这还过不去。还有性质是选择的区间大小不升,并且由每个hi互不相同可以推出长度不为1的区间不会超过O(lognh),其中=minihihi1 (反正我不会证),然后复杂度就是O(nplog(nh))。如果在前面DP时不直接使用高精度运算就可以把复杂度降为O(n(log3nh+p))点评:毒瘤题

20.P3734 [HAOI2017]方案数

题意:一个人从(0,0,0)走到(n,m,r),每一步可以(x,y,z)(x,y,z)(x&x=x)(x,y,z)(x,y,z)(y&y=y)(x,y,z)(x,y,z)(x&z=z),其中有m个障碍点,求方案数。

思路:考虑容斥,用全部的走法减去不合法的走法。先考虑怎么求全部走法。设dp[i][j][k]表示走到点(x,y,z)满足popcount(x)=i,popcount(y)=j,popcount(z)=k的方案数,转移时

dp[i][j][k]=x=0i1dp[x][j][k]×(ix)+x=0j1dp[i][x][k]×(jx)+x=0k1dp[i][j][x]×(kx)

先把所有关键点按字典序排序,然后依次枚举每个障碍点i,设f[i]表示不经过任何障碍点到达i的方案数,因此:

f[i]=dp[popcount(xi)][popcount(yi)][popcount(zi)]j=1i1f[j]×to(j,i)

其中to(j,i)表示从障碍点j到障碍点i的方案数,则

to(j,i)=[(xj&xi=xj),(yj&yi=yj),(zj&zi=zj)]dp[popcount(xi)popcount(xj)][popcount(yi)popcount(yj)][popcount(zi)popcount(zj)]

复杂度O(log4n+m2)

21.CF1119F Niyaz and Small Degrees

题意:一棵大小为n的树,有边权,设f(x)表示要满足所有点的degx所要删掉的边的边权和的最小值,求出f(0)f(n)

思路:先考虑对于每个x计算答案。设dp[i][0/1]表示i向上连的边删或不删时的最小代价。转移时,对于i的每个儿子j,有两种贡献,a1=dp[j][0]+w表示删掉(i,j)的贡献,a2=dp[j][1]表示不删(i,j)的贡献。我们考虑先取所有的a2,用堆来维护所有的a1a2,然后选最小的一些a1a2a2替换掉,这一步可以用堆维护。单次复杂度O(nlogn)

然后考虑正解。如果从小到大考虑每个x,那么一个deg=x的点对[x,n1]是没有贡献的,对于每个点只需考虑x<deg的情况,这样的量级是deg=n的。我们将degx的点视为无用点,其他为有用点,然后从每个有用点开始dfs,把无用点视为叶子,这时每个无用点的a1=w,a2=0,它对它相邻的有用点的贡献即为a1a2=w,然后像暴力做法一样加入有用点的贡献,最后再加上一直弹堆顶到堆中元素为须删掉的边数时,堆中所有a1a2的和就是答案。注意更新答案后要撤销加入的有用点的贡献,并撤销不断弹出堆顶直到堆中元素符合要求时删除的无用点的贡献,需要用可删除堆维护。总(均摊)复杂度O(nlogn)(有个智障调了一上午结果发现可删除堆写错了,警钟敲烂)

22.P3643 [APIO2016] 划艇

题意:有n个位置,每个位置上可以选一个在[li,ri]中间的数,并且要大于它前面任意一个选了的数,也可以不选,求方案数。

思路:先考虑朴素DP。设f[i][j]表示第i个位置选了j的方案数,那么

f[i][j]=f[i1][j]+k=1j1f[i1][k]

我们发现如果把第二维j看作自变量的话,那么可以发现这是一个多项式,而每求一次前缀和次数+1,所以最高是n次多项式,那么我们带入n+1个点值进去就可以得到答案。

复杂度O(n3)

23.CF1268E Happy Cactus

题意:给定一个无向仙人掌,边权互不相同,定义(u,v)是好的当且仅当存在从uv的路径满足边权单调递增,对于所有u求出有多少(u,v)是好的。

思路:首先考虑如果是一棵树怎么做。我们从大到小加边,设fi为答案,每次加的边(x,y)的两端在之前必然无法到达,所以u能到的点多了vv能到的点,即fx=fy=fx+fy+1

然后考虑一般的情况。我们发现,有可能加边的两端已经互相可达,这时会出现重复,而这种情况只可能出现在最小边的两端可以合法到达最大边的环中,设最大边(u,v)的一段为u,那贡献要减去加入这条边时的贡献,即fx=fy=fx+fy+1g[u],其中gu为加入这条边时的贡献,即gu=fu+1。先求出点双然后判断每个点双是否合法即可。

复杂度O(n)

24.CF1239E Turtle

题意:给一个2×n的棋盘和2×n个数,给出把这2×n个数填入棋盘的方案,使得从左上角只向下或右走走到右下角遇到的数的和的最大值最小。

思路:(思维量巨大题) 先找一些性质。首先,假设选好了一行的数,那么肯定是第一行从小到大,第二行从大到小。假设在第k列转向的答案为ansk,那么ansk=ans1+i=1k1wi,其中wi=ai+1bi,即k向右移一位的改变量。容易知道w是递增的,而一开始的w1有可能小于0,那么只有可能在k=1k=n是取到最大值。接着,假设我们选定了a1,bn,那么我们就要选出n1个数使得max(ai+a1,bi+bn)最小,而ai+bi的值是确定的(记为S),假设一个方案ai=x,那bi=Sx,所以最接近S2的一组方案是最优的。这样,我们枚举a1,bn,就得到了O(n4ai)的做法,但明显过不了。我们要让最大值最小,那么一定要让做贡献的数尽量小,所以一个很直观的想法是把最小值和次小值放在a1bn,这样就可以降低复杂度了。

复杂度O(n2ai)

25.P1295 [TJOI2011] 书架

题意:给一个序列h,要分成若干段使得每一段长度不大于m,最小化所有段的最大值之和。(其实这题本来不是这个题单里的)

思路:O(n)的做法太神仙了) 首先可以很简单的想到一个O(n2)的DP:设fi表示i为当前段末尾的最小和,则fi=minsisj<=m(fj+maxk=j+1ihk)。因为有最大值,我们考虑找找单调性。首先,如果hjhj+1,那么maxk=jihk=maxk=j+1ihk,而f显然是单调递增,那这个时候从j转移一定比从j+1转移更优,所以我们很容易用一个单调队列(记为q)来记录可能对答案做贡献的位置。然后我们考虑如何计算贡献。因为队列里的值是递减的,即hql>hqr,那么每个的贡献就是fql+aql+1,这时我们还需维护f。为了保证复杂度,我们可以用两个单调下降的栈来维护f,每当左或右端点到了中点就重构,这样复杂度就是O(n)的了。

26.P8352 [SDOI/SXOI2022] 小 N 的独立集(其实这题本来也不是这个题单里的)

题意:给定大小为n的树,每个点点权可以为[1,k],求最大权独立集大小为i[1,nk]的方案数。

思路:一开始以为是普通的树形dp,后来才发现是dp套dp。首先考虑如果是直接求最大权独立集大小,那么就是设f[x][0/1]表示x点选/不选的最大值,然后f[x][0]=yson(x)max(f[y][0],f[y][1])f[x][1]=val[x]+yson(x)f[y][0],而在计数时,我们考虑将f[x][0]f[y][0]记入状态,设g[x][v0][v1]表示x子树中f[x][0],f[y][0]分别为v0,v1的方案数,这就是一个树上背包的问题,只不过复杂度较高。我们发现这个状态本身就是O(n3k2)的,需要优化,于是我们改变定义,设f[x][1/0]表示是否强制不选点x的答案,我们发现f[x]有一些性质,比如0f[x][0]f[x][1]val[x]k,那么我们就可以简化状态,记g[x][v][d]表示在x的子树中,f[x][0]v+df[x][1]v的方案数,每次转移时有g[x][i+p+q][max(i+j+p,i+p+q)(i+p+q)]+g[x][i][j]×g[y][p][q]g[x][i+p+q][max(i+j+p,i+p+q)(i+p+q)],这样一来复杂度就是O(n2k4)的了。

27.P8329 [ZJOI2022] 树(同上……)

题意:定义两颗树是好的当且仅当第1棵树每个点父亲编号小于它,第2棵树每个点父亲编号大于它,每个点恰好在一棵树上是叶子,求对1~n求方案数。

思路:(不会容斥,好似) 首先考虑设f(S)表示第1棵树非叶集合为S的方案数,第二棵树为g(S),那么很容易推出

ans=ST=,ST={1,2,n}f(S)g(T)

但是f(S)g(S)并不方便直接求,我们考虑容斥。设f(S)表示第一棵树非叶集合S的方案数,g(S)同理,那么可知

ans=ST=,ST={1,2,n}f(S)g(T)=ST=,ST={1,2,n}SS,TTf(S)g(T)(1)|S||S|+|T||T|=ST=f(S)g(T)(1)n|S||T|2n|S||T|=ST=f(S)g(T)(2)n|S||T|

这样似乎比之前的恰好更好处理一些。于是我们设dp[i][j][k]表示|{1,2,i}S|=j,|{i+1,i+2,n}T|=k的方案数。转移时根据i是属于S还是T还是都不属于进行分类讨论即可。

复杂度O(n3)

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

题意:给出a数组以及b数组的总和,求有多少种标号方案,使得按bi从小到大依次加入bi后新加入的ai+bi是当前最大的。

思路:(学到了一个很新的科技) 我们考虑DP的状态应该与那些有关,首先是已经加入了的位置有哪些,这个是O(2n)的,当前加入的数的bi以及总和sum,这样的DP固然带2n×m2,显然不行,我们考虑怎么去掉一维。我们可以发现,一旦确定了顺序,我们就可以贪心地使每次的b尽量小,这也启示我们可以试图去掉当前枚举的bi这一维,只需保证bi不降,即bi的差分数组非负。但是有一个很严重的问题是b是有后效性的,于是我们可以用“费用提前”的trick,把当前选的数对后面的数的影响算出来并减掉,这样就可以避免有后效性了。时间复杂度O(2nn2m)

29.P8497 [NOI2022] 移除石子

题意:有n堆石子,每一堆石子数量在[li,ri]之间,每次操作可以拿走一堆里2个石子或在长度3的区间里每一堆石子拿走一个,求添加恰好k个石子后能把所有石子取空的方案数。

思路:(不愧是NOID1T2,听同学讲后又看了Wei老师的博客才搞懂)

首先考虑如何检验一个局面(k=0)是否合法。首先考虑简化操作。第二个操作显然可以把长度>6的区间拆成由长度为3,4,5的区间拼起来,那么我们就只用考虑这4种操作。其次,我们可以使每一种长度的操作的次数1,因为做相同的操作可以直接用操作1代替。于是就可以考虑DP,设f[i][j][k][l]表示i之前的操作二,有j可以延伸到i,有k必须枚举到i,有l必须枚举到i+1,是否可行。转移时枚举从i开始的操作数量p,再枚举j个中实际延伸到i的数量q,判断aiklpq是否=0>1就是合法的。

这时我们发现,可以将j,k这两维状态合并。我们直接钦定有多少个操作延伸到了i即可。于是,我们改成设f[i][j][k]表示i之前的操作二,有j个钦定延伸到i,有k个钦定延伸到i+1,是否可行。转移时同样枚举从i开始有多少个操作二即可。

这个时候j,k的范围是j6,k3的,我们考虑缩小范围。我们发现,如果同时进行了一次4,5的操作,那这等价于一次操作1和下一个位置的3,4的操作,于是就降到了j4,k2。接着我们枚举从i1延伸到i且在i处长度3的情况可以发现这些可以用不超过2次操作二代替,于是范围就是j2,k2的了。

接着考虑k0的情况。我们发现恰好不好处理,于是改为至多,再容斥一下下,即添加小于k个石子有解,添加k个后无解的方案数。首先k=0无影响,k=1只有n=3&&a1=a2=a3=1ai=0,而当k2时可以归纳证明若添加小于k个石子有解,那么添加k个石子也一定有解(k=1除外)。于是我们设g[i][j][k]表示使f[i][j][k]=1最少需添加的石子数,转移时枚举l,然后从g[i][j][k]+至少要添加的石子数转移到g[i+1][p][l]即可。

接下来就是对k=0计数。因为fi只有9种状态,于是我们考虑DP套DP。设dp[i][S]表示这9种状态取值为S的方案数。为了方便转移,我们设get(S,j)表示从状态为Sfi开始,令ai=j,转移到fi+1的状态。由于g[i][j][k]j,k,l2,因此ai8,这样子贡献就比较好统计了。然后(不知道怎么样子就) 发现6的操作是等价的,于是就可以O(nS)计算了。

最后考虑k>0,因为g[i][j][k]0~101共102种取值,但实际只有S=8765种状态,可以通过。

复杂度:O(nS)(写得好累……有1302个字,比作文还长)


__EOF__

本文作者Xttttr
本文链接https://www.cnblogs.com/Xttttr/p/17120970.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Xttttr  阅读(164)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示