树形DP

[POI2011] DYN-Dynamite

二分 K K K

check(mid):
能否选出 m m m个点,使得 ∀ i 为关键点, M i n j i s s e l e c t e d { d i s ( i , j ) } ≤ m i d \forall i为关键点,Min_{j\ is\ selected}\{dis(i,j)\}\leq mid ∀i为关键点,Minj is selected​{dis(i,j)}≤mid

进一步转化问题:
一棵树上选 t o t tot tot 个点,使得 ∀ i 为关键点, M i n j i s s e l e c t e d { d i s ( i , j ) } ≤ m i d \forall i为关键点,Min_{j\ is\ selected}\{dis(i,j)\}\leq mid ∀i为关键点,Minj is selected​{dis(i,j)}≤mid,最小化 t o t tot tot。若 t o t ≤ m tot\leq m tot≤m则 check(mid) 为 true,否则 check(mid) 为 false

定义点 i i i被点 j j j覆盖,当且仅当 d i s i , j ≤ m i d dis_{i,j}\leq mid disi,j​≤mid
假设当前考虑到以 x x x为根的子树。
对于在 x x x子树内的关键点,它们要么被 x x x子树内的点覆盖,要么还等着被 x x x子树外的点覆盖。
对于第二种情况,我们需要把问题留到考虑 x x x的祖先时再去解决。

设 f x f_x fx​表示 x x x子树内未被覆盖点到 x x x的最远距离,
g x g_x gx​表示 x x x子树内被选择点到 x x x的最近距离。
初值: f x = − ∞ , g x = ∞ f_{x}=-\infty,g_{x}=\infty fx​=−∞,gx​=∞
转移: f x = max ⁡ { f y + 1 } f_x=\max \{f_y+1\} fx​=max{fy​+1}, g x = min ⁡ { f y + 1 } g_x=\min\{f_y+1\} gx​=min{fy​+1}
特判:
若 f x + g x ≤ m i d f_x+g_x\leq mid fx​+gx​≤mid,则 x x x子树内所有点都已经被覆盖, f x ← − ∞ f_x\leftarrow -\infin fx​←−∞
若 f x = m i d f_x=mid fx​=mid,则 x x x一定要选, f x ← − ∞ , g x ← 0 , t o t + + f_x\leftarrow -\infin,g_x\leftarrow 0,tot++ fx​←−∞,gx​←0,tot++
若 g x > m i d a n d x 为关键点 g_x>mid\ and\ x为关键点 gx​>mid and x为关键点,把问题留给 x x x的父亲解决, f x ← m a x ( f x , 0 ) f_x\leftarrow max(f_x,0) fx​←max(fx​,0)
Code

重建道路

设 f [ i ] [ j ] f[i][j] f[i][j]表示以 i i i为根的子树,保留 j j j个点(包括自己),删去的最小边数
初始化: f [ i ] [ 1 ] = s o n [ i ] f[i][1]=son[i] f[i][1]=son[i]( s o n [ i ] son[i] son[i]表示 i i i有几个儿子)
转移: f [ u ] [ j ] = m a x { f ( u , j − k ) + f ( v , k ) − 1 } f[u][j]=max\{f(u,j-k)+f(v,k)-1\} f[u][j]=max{f(u,j−k)+f(v,k)−1}(−1是因为v和u之间相连的那一条边不删)

注意:我们要获得的子树的根并不一定要是整棵树的根节点
Code

城市环路

基环树
如果这道题是出在树上,那就是最大独立集的裸题
设 f [ i ] [ 1 / 0 ] f[i][1/0] f[i][1/0]表示选/不选 i i i ,以 i i i为根的子树的最大贡献
f [ u ] [ 1 ] = ∑ v ∈ s o n u f [ v ] [ 0 ] f[u][1]=\sum_{v\in son_u}f[v][0] f[u][1]=∑v∈sonu​​f[v][0]
f [ u ] [ 0 ] = ∑ v ∈ s o n u m a x ( f [ v ] [ 0 ] , f [ v ] [ 1 ] ) f[u][0]=\sum_{v\in son_u}max(f[v][0],f[v][1]) f[u][0]=∑v∈sonu​​max(f[v][0],f[v][1])

考虑在基环树上怎么做:
法一:强制断边
首先把环找出来
对于环上一对相邻点 ( x , y ) (x,y) (x,y),根据题意, x , y x,y x,y不能同时选

  1. 强制 x x x不选,此时 y y y可选可不选,断掉边 ( x , y ) (x,y) (x,y)无影响。断边后做树形dp, f [ x ] [ 0 ] f[x][0] f[x][0]即为此情况下的答案
  2. 强制 y y y不选,此时 x x x可选可不选,断掉边 ( x , y ) (x,y) (x,y)无影响。断边后做树形dp, f [ y ] [ 0 ] f[y][0] f[y][0]即为此情况下的答案
  3. 最终答案= m a x ( f [ x ] [ 0 ] , f [ y ] [ 0 ] ) max(f[x][0],f[y][0]) max(f[x][0],f[y][0])

Code
法二:树形dp+环形dp
博客
Code

[JSOI2008]魔兽地图

这个题的特殊性在于儿子对于父亲节点是有影响的
所以用 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第 i i i号装备,其中 j j j个被祖先用来合成上层装备,花费 k k k元所能获得最大的力量值。

分步转移,第一步先枚举第 i i i 号装备合成多少个,第二步再合并子树贡献。
Code

[JSOI2016]最佳团体

分数规划
二分答案 m i d mid mid,问题转化为:
给定一棵根为0的树。每点点权为 P i − m i d ∗ S i P_i-mid *S_i Pi​−mid∗Si​,选定一个点就必须选其所有祖先节点。
问能否取 k k k个节点使得取出点的点权和大于零。

设 d p [ u ] [ j ] dp[u][j] dp[u][j]表示以 u u u为根的子树,取 j j j个节点所带来的最大收益
合并就是经典树形背包
Code

[USACO12FEB]Nearby Cows G

基础换根dp
f [ i ] [ j ] f[i][j] f[i][j] 表示 i i i 子树内到 i i i 距离为 j j j 的点的权值和
g [ i ] [ j ] g[i][j] g[i][j] 表示 i i i 子树外到 i i i 距离为 j j j 的点的权值和
Code

CF512D Fox And Travelling

首先,在环中的点一定不会被遍历
用类似拓扑排序的过程可以把环上的点全部扔掉,剩下的点会构成若干个有根树和无根树,其中有根树的根是树中唯一与环中的点相连的点

先考虑有根树,设 f i , j f_{i,j} fi,j​ 表示以 i i i 为根的子树中,选 j j j 个点的方案数
转移: f i , j + k = f p i , j × f s o n , k × ( j + k k ) f_{i,j+k}=fp_{i,j}\times f_{son,k}\times \binom {j+k}{k} fi,j+k​=fpi,j​×fson,k​×(kj+k​)
特别地, f i , s i z i = f i , s i z i − 1 f_{i,siz_i}=f_{i,siz_i-1} fi,sizi​​=fi,sizi​−1​(根节点必须最后删)

对于无根树,感觉可以钦定最后一个被删的是哪个点,但更简单的方法是直接对每个点为根跑一遍有根树的算法,然后发现选 i i i 个点的情况在没被选的 s i z − i siz-i siz−i 个点为根的时候会被统计,因此答案要除以 s i z − i siz-i siz−i(如果全选是特殊情况,不需要除)

然后就是森林合并答案,就用类似合并子树的方法组合数合并就可以了
Code

CF543D Road Improvement

换根dp
根据套路,
我们设 f u f_u fu​为修好以 u u u为根的子树中的路的方案数
g u g_u gu​为修好整棵树中除了以 u u u为根的子树中的路的方案数

先考虑 f u f_u fu​怎么求:
设 f u , 0 f_{u,0} fu,0​表示 u u u子树内无坏边的方案数, f u , 1 f_{u,1} fu,1​表示 u u u子树内有坏边的方案数
f u , 0 = ∏ v ∈ s o n u f v , 0 , f u , 1 = ∏ v ∈ s o n u ( f v , 0 × 2 + f v , 1 ) − 1 f_{u,0}=\prod_{v\in son_u} f_{v,0},f_{u,1}=\prod_{v\in son_u} (f_{v,0}\times 2+f_{v,1})-1 fu,0​=∏v∈sonu​​fv,0​,fu,1​=∏v∈sonu​​(fv,0​×2+fv,1​)−1
发现 f u , 0 = 1 f_{u,0}=1 fu,0​=1,又考虑到 f u = f u , 0 + f u , 1 f_u=f_{u,0}+f_{u,1} fu​=fu,0​+fu,1​,
所以 f u = ∏ v ∈ s o n u ( f v + 1 ) f_u=\prod_{v\in son_u}(f_v+1) fu​=∏v∈sonu​​(fv​+1)

再考虑 g u g_u gu​:
g u = g f a × f f a f u + 1 + 1 = g f a × ∏ x ∈ s o n f a , x ≠ u ( f x + 1 ) + 1 g_u=\frac{g_{fa}\times f_{fa}}{f_u+1}+1=g_{fa}\times\prod_{x\in son_{fa},x\not=u}(f_x+1)+1 gu​=fu​+1gfa​×ffa​​+1=gfa​×∏x∈sonfa​,x=u​(fx​+1)+1
因为逆元不保证存在,所以要记录前缀积和后缀积来避免除法
Code

CF1146F Leaf Partition

博客

CF1016F Road Projects

博客

CF671D Roads in Yusland

博客

CF337D Book of Evil

经典换根dp
设 f [ u ] [ 0 ] f_[u][0] f[​u][0]表示 u u u子树内的点到 u u u的最大/次大距离
g [ u ] [ 0 ] g_[u][0] g[​u][0]表示 u u u子树外的点到 u u u的最大/次大距离

CF23E Tree

博客

CF708C Centroids

博客

其他DP

[WC2008] 游览计划

斯坦纳树
模板

斯坦纳树问题:

给出一个有 n n n 个点 m m m 条边的有权无向图,然后选定 k k k 个点,让你求出使这 k k k 个点联通所需的最小代价

求解:

首先,答案的子图一定是树

设 d p [ i ] [ S ] dp[i][S] dp[i][S] 表示以 i i i 为根的一棵树,包含集合 S S S 中所有点的最小代价。

转移:

对于 i i i 的度数为 1 的情况,可以考虑枚举树上与 i i i 相邻的点 j j j,则
d p ( j , s ) + w ( j , i ) − > d p ( i , s ) dp(j,s)+w(j,i)−>dp(i,s) dp(j,s)+w(j,i)−>dp(i,s)
对于 i i i 的度数大于 1 的情况,可以划分成几个子树考虑,则
d p ( i , T ) + d p ( i , S − T ) − > d p ( i , S ) ( T ⊆ S ) dp(i,T)+dp(i,S−T)−>dp(i,S)(T\subseteq S) dp(i,T)+dp(i,S−T)−>dp(i,S)(T⊆S)

对于第1种转移,可以想到最短路模型的三角形不等式,对于每一个 S S S ,将图做一次松弛操作即可。具体可以用 dijkstra 或 spfa 实现。
对于第2种转移,枚举子集即可。

如何优秀的枚举子集:
一个非常trivial的做法:

for(int sta=0;sta<=MAX;sta++){for(int s=0;s<=MAX;s++){if(s&sta==s){//to do sth}}
}

时间复杂度 O ( 4 n ) O(4^n) O(4n)
更优秀的实现:

for(int sta=0;sta<=MAX;sta++){for(int s=(sta-1)&sta;s;s=(s-1)&sta){//to do sth}
}

时间复杂度 ∑ s t a 2 ∣ ∣ s t a ∣ ∣ = ∑ i = 0 n C n i 2 i = 3 n \sum_{sta}2^{||sta||}=\sum_{i=0}^{n}C_{n}^{i}2^i=3^n ∑sta​2∣∣sta∣∣=∑i=0n​Cni​2i=3n
Code

[COCI2011-2012 6]

SOS DP+容斥

首先发现 m m m 很小,于是直接对于每一个箱子状压
于是问题转化为选若干个数使它们按位或为全集
继续转化一下,把每个箱子取个反,问题就变成了选若干个数使它们按位与为空集

设 g [ S ] g[S] g[S] 为有多少种选数方案使 S S S为选出数的按位与的子集
答案为 ∑ S ( − 1 ) ∣ ∣ S ∣ ∣ g [ S ] \sum_{S}(-1)^{||S||}g[S] ∑S​(−1)∣∣S∣∣g[S]

设 f [ S ] f[S] f[S] 为有多少个箱子,使 S S S为其代表的数 A [ i ] A[i] A[i]的子集
g [ S ] = 2 f [ S ] − 1 g[S]=2^{f[S]}-1 g[S]=2f[S]−1

求 f [ S ] f[S] f[S]:
法一:直接枚举子集

for(int sta=0;sta<=MAX;sta++){for(int s=(sta-1)&sta;s;s=(s-1)&sta){//to do sth}
}

时间复杂度 O ( 3 m ) O(3^m) O(3m)
法二:高维前缀和解决这类子集问题

for(int i=0;i<m;i++){for(int s=0;s<(1<<m);s++){if(s&(1<<i)){f[s^(1<<i)]+=f[s];//与标准sos dp方程相比,这里的语句反过来了}}
}

时间复杂度 O ( m 2 m ) O(m2^m) O(m2m)
这种方法又称为SOS DP:博客1 博客2
Code

[CF383E] Vowels

法一:​SOS DP
正难则反,考虑统计不合法单词数
让每个单词对应一个状态 A A A,第 i i i位表示第 i i i个字母是否在单词中出现(1为出现)
记元音字母集的补集为 B B B
则不合法单词对应的 A A A均为 B B B的子集
设 f [ S ] f[S] f[S]表示有多少个单词,其对应的 A A A为 S S S的子集,可以用sos dp求出:

for(int i=0;i<m;i++){for(int s=0;s<(1<<m);s++){if(s&(1<<i)){f[s]+=f[s^(1<<i)];//标准sos dp方程}}
}

答案即为 ( n − f [ S ] ) 2 (n-f[S])^2 (n−f[S])2的异或和
Code

法二:SOS DP+容斥
设 g [ S ] g[S] g[S]为元音集合为 S S S时的合法单词数
设 f [ s ] f[s] f[s]为有多少个单词,使 s s s为其代表的 A A A的子集
即 f [ s ] = ∑ i = 1 n [ s ∈ w o r d i ] f[s]=\sum_{i=1}^{n}[s\in word_i] f[s]=∑i=1n​[s∈wordi​]
g [ S ] = ∑ s ∈ S ( − 1 ) ∣ ∣ s ∣ ∣ + 1 f [ s ] g[S]=\sum_{s\in S}(-1)^{||s||+1}f[s] g[S]=∑s∈S​(−1)∣∣s∣∣+1f[s]
但是这样做的时间复杂度是 O ( 3 24 ) O(3^{24}) O(324),会TLE,所以我们转换一下:
令 f [ s ] = ∑ i = 1 n ( − 1 ) ∣ ∣ s ∣ ∣ + 1 [ s ∈ w o r d i ] f[s]=\sum_{i=1}^{n}(-1)^{||s||+1}[s\in word_i] f[s]=∑i=1n​(−1)∣∣s∣∣+1[s∈wordi​]
则 g [ S ] = ∑ s ∈ S f [ s ] g[S]=\sum_{s\in S}f[s] g[S]=∑s∈S​f[s]
求 f [ s ] f[s] f[s]的复杂度是 O ( n ⋅ 2 3 ) O(n\cdot 2^3) O(n⋅23)(对于每一个单词,枚举其子集)
求 g [ S ] g[S] g[S]的复杂度是 O ( 24 ⋅ 2 24 ) O(24\cdot 2^{24}) O(24⋅224)(sos dp)
Code

[CF449D] Jzzhu and Numbers

法一:SOS DP+容斥
同COCI2011-2012 6
设 g [ S ] g[S] g[S] 为有多少种选数方案使 S S S为选出数的按位与的子集
答案为 ∑ S ( − 1 ) ∣ ∣ S ∣ ∣ g [ S ] \sum_{S}(-1)^{||S||}g[S] ∑S​(−1)∣∣S∣∣g[S]
设 f [ S ] f[S] f[S] 为有多少个箱子,使 S S S为其代表的数 A [ i ] A[i] A[i]的子集
g [ S ] = 2 f [ S ] − 1 g[S]=2^{f[S]}-1 g[S]=2f[S]−1
Code

法二:FWT
设 d p [ i ] [ s ] dp[i][s] dp[i][s]为从前 i i i个数中选择,有多少种选数方案使选出数的按位与为 s s s
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + ∑ k & a [ i ] = = j d p [ i − 1 ] [ k ] dp[i][j]=dp[i-1][j]+\sum_{k\&a[i]==j}dp[i-1][k] dp[i][j]=dp[i−1][j]+∑k&a[i]==j​dp[i−1][k]
d p [ s & a [ i ] ] + = d p [ s ] dp[s\&a[i]]+=dp[s] dp[s&a[i]]+=dp[s]
发现这个柿子本质上就是一个和卷积,可以用FWT解决
博客

[CF348D] Turtles

LGV引理
Code

[USACO20OPEN]Exercise G

循环了几次可以回到原地,当且仅当形成了一个环,假设每个环的长度是 a i a_i ai​,那么 k = lcm ⁡ a i k=\operatorname{lcm}a_i k=lcmai​

又知道 lcm ⁡ a i \operatorname{lcm}a_i lcmai​ 其实就是将所有 a i a_i ai​分解质因数,然后取每个质数的最高次幂乘起来,
所以我们可以想到枚举素数来做dp

设 f [ i ] [ j ] f[i][j] f[i][j] 表示前 i i i 个素数总和为 j j j 的所有 K K K 的总和

枚举第 i i i 个素数的幂进行转移:
f [ i ] [ j ] = ∑ f [ i − 1 ] [ j − p i k ] × p i k f[i][j]=\sum f[i-1][j-p_i^k]\times p_i^k f[i][j]=∑f[i−1][j−pik​]×pik​

可以滚动数组减掉一维
Code

双倍经验:[SCOI2009]游戏 博客

OSU!

设 d p [ i ] dp[i] dp[i]表示到了第 i i i个位置的期望得分,
f [ l ] f[l] f[l]表示第 i i i个位置之前有长度为 l l l的连续1串的概率,
p [ i ] p[i] p[i]表示 i i i为1的概率,
则有转移:
d p [ i ] = d p [ i − 1 ] + p [ i ] ∑ l f [ l ] ( ( l + 1 ) 3 − l 3 ) = d p [ i − 1 ] + p [ i ] ∑ l f [ l ] ( 3 l 2 + 3 l + 1 ) dp[i]=dp[i-1]+p[i]\sum_lf[l]((l+1)^3-l^3)=dp[i-1]+p[i]\sum_l f[l](3l^2+3l+1) dp[i]=dp[i−1]+p[i]∑l​f[l]((l+1)3−l3)=dp[i−1]+p[i]∑l​f[l](3l2+3l+1)

于是考虑维护
E l = ∑ l f [ l ] ⋅ l E_l=\sum_lf[l]\cdot l El​=∑l​f[l]⋅l
E l 2 = ∑ l f [ l ] ⋅ l 2 E_{l^2}=\sum_lf[l]\cdot l^2 El2​=∑l​f[l]⋅l2

则总转移方程为:
E l [ i ] = p [ i ] ∑ l f [ l ] ( l + 1 ) = p [ i ] ( E l [ i − 1 ] + ∑ l f [ l ] ) = p [ i ] ( E l [ i − 1 ] + 1 ) E_l[i]=p[i]\sum_lf[l](l+1)=p[i](E_l[i-1]+\sum_lf[l])=p[i](E_l[i-1]+1) El​[i]=p[i]∑l​f[l](l+1)=p[i](El​[i−1]+∑l​f[l])=p[i](El​[i−1]+1)
E l 2 [ i ] = p [ i ] ∑ l f [ l ] ( l 2 + 2 l + 1 ) = p [ i ] ( E l 2 [ i − 1 ] + 2 E l [ i − 1 ] + 1 ) E_{l^2}[i]=p[i]\sum_lf[l](l^2+2l+1)=p[i](E_{l^2}[i-1]+2E_{l}[i-1]+1) El2​[i]=p[i]∑l​f[l](l2+2l+1)=p[i](El2​[i−1]+2El​[i−1]+1)
d p [ i ] = d p [ i − 1 ] + p [ i ] ( 3 E l 2 [ i − 1 ] + 3 E l [ i − 1 ] + 1 ) dp[i]=dp[i-1]+p[i](3E_{l^2}[i-1]+3E_l[i-1]+1) dp[i]=dp[i−1]+p[i](3El2​[i−1]+3El​[i−1]+1)
Code

收集邮票

设 f [ i ] f[i] f[i]表示已经取到了 i i i种邮票,要取完剩余邮票的期望次数,
a n s [ i ] ans[i] ans[i]表示已经取到了 i i i种邮票,要取完剩余邮票的期望价格

f [ i ] = i n f [ i ] + n − i n f [ i + 1 ] + 1 f[i]=\frac{i}{n}f[i]+\frac{n-i}{n}f[i+1]+1 f[i]=ni​f[i]+nn−i​f[i+1]+1
⇒ f [ i ] = f [ i + 1 ] + n n − i \Rightarrow f[i]=f[i+1]+\frac{n}{n-i} ⇒f[i]=f[i+1]+n−in​
a n s [ i ] = i n ( a n s [ i ] + f [ i ] + 1 ) + n − i n ( a n s [ i + 1 ] + f [ i + 1 ] + 1 ) ans[i]=\frac{i}{n}(ans[i]+f[i]+1)+\frac{n-i}{n}(ans[i+1]+f[i+1]+1) ans[i]=ni​(ans[i]+f[i]+1)+nn−i​(ans[i+1]+f[i+1]+1)
⇒ a n s [ i ] = a n s [ i + 1 ] + f [ i + 1 ] + i n − i f [ i ] + n n − i \Rightarrow ans[i]=ans[i+1]+f[i+1]+\frac{i}{n-i}f[i]+\frac{n}{n-i} ⇒ans[i]=ans[i+1]+f[i+1]+n−ii​f[i]+n−in​

注意: a n s [ i ] ≠ ( f [ i ] + 1 ) f [ i ] 2 ans[i]\not=\frac{(f[i]+1)f[i]}{2} ans[i]=2(f[i]+1)f[i]​,理由如下:
a n s [ i ] = ∑ c n t p c n t ( c n t + 1 ) c n t 2 ans[i]=\sum_{cnt}p_{cnt}\frac{(cnt+1)cnt}{2} ans[i]=∑cnt​pcnt​2(cnt+1)cnt​
( f [ i ] + 1 ) f [ i ] 2 = ( ∑ c n t p c n t c n t + 1 ) ∑ c n t p c n t c n t 2 \frac{(f[i]+1)f[i]}{2}=\frac{(\sum_{cnt}p_{cnt}cnt+1)\sum_{cnt}p_{cnt}cnt}{2} 2(f[i]+1)f[i]​=2(∑cnt​pcnt​cnt+1)∑cnt​pcnt​cnt​
Code

[CF605E] Intergalaxy Trips

设 f [ i ] f[i] f[i]为从 i i i走到 n n n的期望耗时

考虑转移:
首先,我们一定不会找比当前点更劣的点转移,因为这还没有留在原地划算
其次,如果可以转移,那么转移到某点的唯一可能是比它优的点都转移不到
f [ i ] = 1 + f [ i ] ∏ j , f j < f i ( 1 − p i , j ) + ∑ j , f j < f i f [ j ] p i , j ∏ k , p k < p j ( 1 − p i , k ) f[i]=1+f[i]\prod_{j,f_j<f_i}(1-p_{i,j})+\sum_{j,f_j<f_i}f[j]p_{i,j}\prod_{k,p_k<p_j}(1-p_{i,k}) f[i]=1+f[i]∏j,fj​<fi​​(1−pi,j​)+∑j,fj​<fi​​f[j]pi,j​∏k,pk​<pj​​(1−pi,k​)

⇒ f [ i ] = 1 + ∑ j , f j < f i f [ j ] p i , j ∏ k , p k < p j ( 1 − p i , k ) 1 − ∏ j , f j < f i ( 1 − p i , j ) \Rightarrow f[i]=\frac{1+\sum_{j,f_j<f_i}f[j]p_{i,j}\prod_{k,p_k<p_j}(1-p_{i,k})}{1-\prod_{j,f_j<f_i}(1-p_{i,j})} ⇒f[i]=1−∏j,fj​<fi​​(1−pi,j​)1+∑j,fj​<fi​​f[j]pi,j​∏k,pk​<pj​​(1−pi,k​)​

实现:朴素版Dijkstra
博客
Code

常见优化与综合运用

[CF939F] Cutlet

设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 r i r_i ri​ 分钟,把现在煎的面叫做正面,背面煎了 j j j 分钟的最小翻面次数
显然只会在一个区间至多翻 2 次:
不翻面, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
翻了一次,枚举正面煎了 k k k 秒, d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ r − j − k ] + 1 ) dp[i][j] = min(dp[i-1][r-j-k] + 1) dp[i][j]=min(dp[i−1][r−j−k]+1)
翻了两次,枚举背面煎了 k k k 秒, d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j − k ] + 2 ) dp[i][j] = min(dp[i-1][j-k] + 2) dp[i][j]=min(dp[i−1][j−k]+2)

分别用单调队列维护即可

一句话解释单调队列优化dp:如果一个人比你年轻,还比你强,那你就永远打不过他了.jpg

Code

[CF311B] Cats Transport

因为对于任意一只猫,我们都可以直接算出如果有一个人要恰好接走它,需要在哪一时刻出发,我们设第i只猫对应的这个时刻为 t i t_{i} ti​

对于第 i i i只猫,我们定义 t i t_{i} ti​表示如果有人在 t i t_{i} ti​时刻出发,此猫无须等待即可被接走
题目转化为:
现有 p p p个人,要求为每个人指定一个出发时间 a j a_j aj​,最小化 ∑ i = 1 m ( x i − t i ) \sum_{i=1}^{m}(x_i-t_i) ∑i=1m​(xi​−ti​)( x i = M i n a j ≥ t i { a j } x_i=Min_{a_j\geq t_i}\{a_j\} xi​=Minaj​≥ti​​{aj​})

观察到每个人的出发时间 a j a_j aj​必是 t i t_i ti​中的一个
那么假设第 x x x个人的出发时间是 t i t_i ti​,第 x − 1 x-1 x−1个人的出发时间是 t j t_j tj​,
则第 x x x个人会接走第 j + 1 j+1 j+1到第 i i i只猫
题目转化为:
现有 p p p个人,要求为每个人选一只猫 b j b_j bj​,最小化 ∑ j = 1 p ∑ i = b j − 1 + 1 b j ( t b j − t i ) \sum_{j=1}^{p}\sum_{i=b_{j-1}+1}^{b_j}(t_{b_j}-t_i) ∑j=1p​∑i=bj−1​+1bj​​(tbj​​−ti​)

设 f [ i ] [ j ] f[i][j] f[i][j]表示考虑到第 i i i个人,这个人选择了第 j j j只猫的最小代价
记 s [ i ] = ∑ k = 1 i t k s[i]=\sum_{k=1}^{i}t_k s[i]=∑k=1i​tk​
则 f [ i ] [ j ] f[i][j] f[i][j]有转移式:
f [ i ] [ j ] = M i n { f [ i − 1 ] [ k ] + t j ( j − k ) − ( s [ j ] − s [ k ] ) } f[i][j]=Min\{f[i-1][k]+t_j(j-k)-(s[j]-s[k])\} f[i][j]=Min{f[i−1][k]+tj​(j−k)−(s[j]−s[k])}

斜率优化求 f [ i ] [ j ] f[i][j] f[i][j]:
f [ i ] [ j ] = f [ i − 1 ] [ k ] + t j ( j − k ) − ( s [ j ] − s [ k ] ) f[i][j]=f[i-1][k]+t_j(j-k)-(s[j]-s[k]) f[i][j]=f[i−1][k]+tj​(j−k)−(s[j]−s[k])
⟺ f [ i − 1 ] [ k ] + s [ k ] = t j ⋅ k + f [ i ] [ j ] + s [ j ] − t j j \iff f[i-1][k]+s[k]=t_j\cdot k+f[i][j]+s[j]-t_jj ⟺f[i−1][k]+s[k]=tj​⋅k+f[i][j]+s[j]−tj​j
把 f [ i − 1 ] [ k ] + s [ k ] f[i-1][k]+s[k] f[i−1][k]+s[k]看成 y y y, k k k看成 x x x, t j t_j tj​看成 k k k, f [ i ] [ j ] + s [ j ] − t j j f[i][j]+s[j]-t_jj f[i][j]+s[j]−tj​j看成 b b b
现要找到一个点 P ( k , f [ i − 1 ] [ k ] + s [ k ] ) P(k,f[i-1][k]+s[k]) P(k,f[i−1][k]+s[k])使得 b b b最小
维护一个下凸壳,并在凸包上找最优决策点 P P P即可
因为 k k k单增,所以可以用单调队列实现
Code

[NOI2009] 诗人小G

设 f i f_i fi​表示对前 i i i个句子排版后的最小不协调度
记 s i = ∑ j = 1 i ( l e n j + 1 ) s_i=\sum_{j=1}^i(len_j+1) si​=∑j=1i​(lenj​+1),则
f i = m i n j = 0 i − 1 { f j + ∣ s i − s j − 1 − L ∣ P } f_i=min_{j=0}^{i-1}\{f_j+|s_i-s_j-1-L|^P\} fi​=minj=0i−1​{fj​+∣si​−sj​−1−L∣P}
这条转移式是有决策单调性的

感性证明:
记 h j ( x ) = ∣ x − s j − 1 − L ∣ P h_j(x)=|x-s_j-1-L|^P hj​(x)=∣x−sj​−1−L∣P
不难看出 h j h_j hj​关于直线 x = s j + 1 + L x=s_j+1+L x=sj​+1+L对称

对于 x > s j + 1 + L x>s_j+1+L x>sj​+1+L的部分:
h j ( x ) = ( x − s j − 1 − L ) P h_j(x)=(x-s_j-1-L)^P hj​(x)=(x−sj​−1−L)P
h j ′ ( x ) = P ( x − s j − 1 − L ) P − 1 h_j'(x)=P(x-s_j-1-L)^{P-1} hj′​(x)=P(x−sj​−1−L)P−1
所以 h j ′ ( x ) h_j'(x) hj′​(x)在 ( s j + 1 + L , + ∞ ) (s_j+1+L,+\infin) (sj​+1+L,+∞)上单增且恒大于0

对于 x < s j + 1 + L x<s_j+1+L x<sj​+1+L的部分:
根据对称性, h j ′ ( x ) h_j'(x) hj′​(x)在 ( − ∞ , s j + 1 + L ) (-\infin,s_j+1+L) (−∞,sj​+1+L)上同样单增且恒小于0

又因为函数连续,所以 h j ′ ( x ) h_j'(x) hj′​(x)在 R \R R上单增

又因为 h j 1 ( x ) = h j ( x + s j − s j 1 ) h_{j_1}(x)=h_j(x+s_j-s_{j_1}) hj1​​(x)=hj​(x+sj​−sj1​​),即不同的 h j ( x ) h_j(x) hj​(x)之间可以通过平移得到,
所以 ∀ j 1 ≠ j 2 \forall j_1\not=j_2 ∀j1​=j2​, h j 1 ( x ) h_{j_1}(x) hj1​​(x)与 h j 2 ( x ) h_{j_2}(x) hj2​​(x)最多一个交点

意会一下吧
所以 f f f 的转移式满足决策单调性
%%%FlashHu大佬

严谨证明:
证明 w ( j , i ) = ∣ s i − s j − 1 − L ∣ P w(j,i)=|s_i-s_j-1-L|^P w(j,i)=∣si​−sj​−1−L∣P满足四边形不等式,本蒟蒻不会
贴个博客吧
Code

[CF868F] Yet Another Minimization Problem

设 d p i , j dp_{i,j} dpi,j​表示将序列的前 i i i个数划分成 j j j段所需要的最小费用,
设 w l , r w_{l,r} wl,r​表示将 l l l到 r r r划分成一段所需要的花费
显然有转移方程: d p i , j = m i n { d p x , j − 1 + w x + 1 , i } dp_{i,j} =min\{dp_{x,j-1}+w_{x+1,i}\} dpi,j​=min{dpx,j−1​+wx+1,i​}

决策单调性证明:
法一(四边形不等式):
要证 d p dp dp的转移具有决策单调性
即证 ∀ a < b , w ( a , b ) + w ( a + 1 , b + 1 ) ≤ w ( a , b + 1 ) + w ( a + 1 , b ) \forall a<b,w(a,b)+w(a+1,b+1)\leq w(a,b+1)+w(a+1,b) ∀a<b,w(a,b)+w(a+1,b+1)≤w(a,b+1)+w(a+1,b)
即证 ∀ a < b , w ( a , b ) − w ( a + 1 , b ) ≤ w ( a , b + 1 ) − w ( a + 1 , b + 1 ) \forall a<b,w(a,b)-w(a+1,b)\leq w(a,b+1)-w(a+1,b+1) ∀a<b,w(a,b)−w(a+1,b)≤w(a,b+1)−w(a+1,b+1)
即把区间从 [ a + 1 , b ] [a+1,b] [a+1,b]拓到 [ a , b ] [a,b] [a,b]的增量 ≤ \leq ≤把区间从 [ a + 1 , b + 1 ] [a+1,b+1] [a+1,b+1]拓到 [ a , b + 1 ] [a,b+1] [a,b+1]的增量
该式显然正确,因为在区间中增加一个元素,它对答案的贡献与区间内与它值相同的元素数量有关
法二:
记 c x [ i ] c_x[i] cx​[i]为区间 [ 1 , i ] [1,i] [1,i]中值为 j j j的元素个数
h j ( i ) = w ( j + 1 , i ) = ∑ x ( c x [ i ] − c x [ j ] ) ( c x [ i ] − c x [ j ] − 1 ) 2 h_j(i)=w(j+1,i)=\sum_{x}\frac{(c_x[i]-c_x[j])(c_x[i]-c_x[j]-1)}{2} hj​(i)=w(j+1,i)=∑x​2(cx​[i]−cx​[j])(cx​[i]−cx​[j]−1)​
因为 ( c x [ i ] − c x [ j ] ) ( c x [ i ] − c x [ j ] − 1 ) 2 \frac{(c_x[i]-c_x[j])(c_x[i]-c_x[j]-1)}{2} 2(cx​[i]−cx​[j])(cx​[i]−cx​[j]−1)​的导函数单增,所以合起来就可以得出 h j ′ ( i ) h_j'(i) hj′​(i)单增
结合图像可以证明 d p dp dp的转移具有决策单调性

实现:
因为 c o s t ( j , i ) cost(j,i) cost(j,i)不好快速计算,不适合用二分栈来做,所以这题是用分治实现的
Code

[SDOI2016]征途

高中数学告诉我们: s 2 = x 2 ‾ − x ‾ 2 s^2=\overline {x^2}-{\overline x}^2 s2=x2−x2
所以 m 2 s 2 = m ∑ v i 2 − ( ∑ v i ) 2 m^2s^2=m\sum v_i^2-(\sum v_i)^2 m2s2=m∑vi2​−(∑vi​)2
− ( ∑ v i ) 2 -(\sum v_i)^2 −(∑vi​)2为定值,我们只要令 ∑ v i 2 \sum v_i^2 ∑vi2​最小即可
设 f [ i ] [ j ] f[i][j] f[i][j]表示把前 i i i段路分为 j j j天走, ∑ k = 1 j v k 2 \sum_{k=1}^{j}v_k^2 ∑k=1j​vk2​的最小值
记 s i s_i si​表示前 i i i段路的长度和
则 f [ i ] [ j ] f[i][j] f[i][j]有转移式: f [ i ] [ j ] = m i n { f [ x ] [ j − 1 ] + ( s i − s x ) 2 } f[i][j]=min\{f[x][j-1]+(s_i-s_x)^2\} f[i][j]=min{f[x][j−1]+(si​−sx​)2}

斜率优化:
f [ i ] [ j ] = f [ x ] [ j − 1 ] + ( s i − s x ) 2 f[i][j]=f[x][j-1]+(s_i-s_x)^2 f[i][j]=f[x][j−1]+(si​−sx​)2
⟺ 2 s i s x + f [ i ] [ j ] − s i 2 = f [ x ] [ j − 1 ] + s x 2 \iff 2s_is_x+f[i][j]-s_i^2=f[x][j-1]+s_x^2 ⟺2si​sx​+f[i][j]−si2​=f[x][j−1]+sx2​
把 2 s i 2s_i 2si​看成 k k k, s x s_x sx​看成 x x x, f [ i ] [ j ] − s i 2 f[i][j]-s_i^2 f[i][j]−si2​看成 b b b, f [ x ] [ j − 1 ] + s x 2 f[x][j-1]+s_x^2 f[x][j−1]+sx2​看成 y y y
找最优决策点即找到点 ( s x , f [ x ] [ j − 1 ] + s x 2 ) (s_x,f[x][j-1]+s_x^2) (sx​,f[x][j−1]+sx2​)使得 b b b最小
Code

[HNOI2011]数学作业

容易得到递推式: f [ n ] = f [ n − 1 ] × 1 0 l e n ( n ) + n m o d m f[n]=f[n-1]\times 10^{len(n)}+n \mod m f[n]=f[n−1]×10len(n)+nmodm
构造转移矩阵:
[ f [ n ] n 1 ] = [ f [ n − 1 ] n − 1 1 ] × [ 1 0 l e n ( n ) 0 0 1 1 0 1 1 1 ] \begin{bmatrix} f[n]&n&1\end{bmatrix}=\begin{bmatrix}f[n-1]&n-1&1\end{bmatrix}\times\begin{bmatrix}10^{len(n)}&0&0\\1&1&0\\1&1&1\end{bmatrix} [f[n]​n​1​]=[f[n−1]​n−1​1​]×⎣ ⎡​10len(n)11​011​001​⎦ ⎤​
如果不是 1 0 l e n ( n ) 10^{len(n)} 10len(n)这个奇怪的变量,这道题已经做完了
那我们干脆把 1 0 l e n ( n ) 10^{len(n)} 10len(n)变成常量:枚举位数,对每一个位数做一次矩阵快速幂

[USACO07NOV]Cow Relays G

经典结论:
用矩阵 A A A表示有向图 G G G的连通情况( A i , j = 1 A_{i,j}=1 Ai,j​=1表示 G G G中存在边 i → j i\to j i→j)
那么从 s s s到 t t t经过 k k k条边的路径数= ( A k ) s , t (A^k)_{s,t} (Ak)s,t​

拓展到本题:
我们定义一种新运算 ∗ * ∗:
[ a 1 , 1 a 1 , 2 ⋯ a 1 , m a 2 , 1 a 2 , 2 ⋯ a 2 , m ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , m ] ∗ [ b 1 , 1 b 1 , 2 ⋯ b 1 , n b 2 , 1 b 2 , 2 ⋯ b 2 , n ⋮ ⋮ ⋱ ⋮ b m , 1 b m , 2 ⋯ b m , n ] = [ c 1 , 1 c 1 , 2 ⋯ c 1 , n c 2 , 1 c 2 , 2 ⋯ c 2 , n ⋮ ⋮ ⋱ ⋮ c n , 1 c n , 2 ⋯ c n , n ] \begin{bmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,m}\\a_{2,1}&a_{2,2}&\cdots&a_{2,m}\\\vdots&\vdots&\ddots&\vdots\\a_{n,1}&a_{n,2}&\cdots&a_{n,m}\end{bmatrix} * \begin{bmatrix} b_{1,1}&b_{1,2}&\cdots&b_{1,n}\\b_{2,1}&b_{2,2}&\cdots&b_{2,n}\\\vdots&\vdots&\ddots&\vdots\\b_{m,1}&b_{m,2}&\cdots&b_{m,n}\end{bmatrix} =\begin{bmatrix} c_{1,1}&c_{1,2}&\cdots&c_{1,n}\\c_{2,1}&c_{2,2}&\cdots&c_{2,n}\\\vdots&\vdots&\ddots&\vdots\\c_{n,1}&c_{n,2}&\cdots&c_{n,n}\end{bmatrix} ⎣ ⎡​a1,1​a2,1​⋮an,1​​a1,2​a2,2​⋮an,2​​⋯⋯⋱⋯​a1,m​a2,m​⋮an,m​​⎦ ⎤​∗⎣ ⎡​b1,1​b2,1​⋮bm,1​​b1,2​b2,2​⋮bm,2​​⋯⋯⋱⋯​b1,n​b2,n​⋮bm,n​​⎦ ⎤​=⎣ ⎡​c1,1​c2,1​⋮cn,1​​c1,2​c2,2​⋮cn,2​​⋯⋯⋱⋯​c1,n​c2,n​⋮cn,n​​⎦ ⎤​
其中 c i , j = M i n k = 1 m { a i , k + b k , j } c_{i,j}=Min_{k=1}^m{}\{a_{i,k}+b_{k,j}\} ci,j​=Mink=1m​{ai,k​+bk,j​}
因为 ∗ * ∗运算满足结合律,所以 A ∗ A ∗ A ∗ ⋯ ∗ A A*A*A*\cdots *A A∗A∗A∗⋯∗A仍然可以用快速幂求得

在这种新运算下,如果初始矩阵中 A i , j A_{i,j} Ai,j​表示 i i i到 j j j的最小距离
那么从 s s s到 t t t经过 k k k条边的最短路径长度= ( A k ) s , t (A^k)_{s,t} (Ak)s,t​(这里的 A k A^k Ak表示 k k k个 A A A相 ∗ * ∗)
博客

[SCOI2014]方伯伯的玉米田

首先本题需要确定一个事实:
每一次的拔高操作区间右端点一定是最右边的玉米

设 f [ i ] [ j ] f[i][j] f[i][j]表示以 i i i 结尾, i i i 这个点已经被 j j j 个拔高区间覆盖过,所能得到的最长不下降序列长度
f [ i ] [ j ] = m a x { f [ k ] [ l ] } + 1 ( 1 ≤ k < i , 0 ≤ l ≤ j , h [ i ] + j ≥ h [ l ] [ k ] f[i][j]=max\{f[k][l]\}+1(1\leqk<i,0\leq l\leq j,h[i]+j\geq h[l][k] f[i][j]=max{f[k][l]}+1(1≤k<i,0≤l≤j,h[i]+j≥h[l][k]

用数据结构优化转移即可
Code

[NOIP2018 提高组] 保卫王国

博客
Code

NOIP复健计划——动态规划相关推荐

  1. (复健计划)Python列表

    这里总结了近日学习python中,列表与元祖的一些基础知识 列表的结构与基本下标: list = [100,45,23] 这是一个简单的列表,通过list[数字]可以调用列表中的元素,与C中的数组使用 ...

  2. (复健计划)标准库类型string

    标准库类型string表示可变长的字符序列,使用string类型必须包含sring头文件<string>.作为标准库的一部分,string定义在命名空间,string定义在命名空间std中 ...

  3. (复健计划)python中的字典

    以下总结了近日学习中python字典的一些基本知识 python中的字典也包括了一系列的类似配对叫做键值对, 配对的名字叫键名,值称为键值,例如: dict = {'key': 100, 'key2' ...

  4. 个人向前端知识“复健”

    let obj = { a: 1, b: 2 }; Object.prototype.c = 3; // 所有obj添加c Object.defineProperty(obj, 'd', { enum ...

  5. 2019NOIP算法复健+学习

    前言: 原本因为kma太弱,很多算法没学学了也不会用,打算设置密码给自己看.后来想了想,觉得也没有必要,既然决定了要学些东西到脑子里,就没什么好丢人的. 注:"×"意为完全没学,& ...

  6. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告

    [NOIP 2015]运输计划 题面: A[NOIP2015 Day2]运输计划 时间限制 : 20000 MS 空间限制 : 262144 KB 问题描述 公元 2044 年,人类进入了宇宙纪元. ...

  7. 前端复健(微信小程序)

    前端复健 WXML语言(HTML衍生物) 分为成对出现和不成对出现 属性设置 <关键词 属性名称="属性值"> 通用属性:样式,id,响应函数,参数传递 class中的 ...

  8. JAVA复健DateNote.001

    JAVA复健手术第一天 jdk环境配置 1,安装jdk,同时记住java文件安装目录2,设置环境变量 编辑PATH变量,在末尾加上 %JAVA_HOME%\bin; 新建CLASSPATH %JAVA ...

  9. 【综合复健训练2021/1/18:题解】Comprehensive Training (CF 1000 ~ 1600)

    Comprehensive Training (CF 1000 ~ 1600) 前言 A:贪心 1600 B:排序+贪心 1400 C:二分+贪心 1800 D:博弈 1200 F:DFS搜索 160 ...

最新文章

  1. matlab and操作,系统建模 | Control Tutorials for Matlab and Simulink
  2. dfinity什么时候发币_区块链3.0的Dfinity揭秘
  3. 理解 Azure AD 安全默认值设置
  4. Flink运行时架构
  5. Flex里Application和TitleWindow数据交互方法
  6. java支付宝第三方支付详解
  7. iOS WKWebView与JS交互传值
  8. paip.c++ bcb string 转换操作大总结.
  9. 从文本中提取单词生成单词本
  10. 发家致富:爬取双色球信息并统计
  11. DIY四旋翼(穿越机)软硬件设计
  12. 冯诺依曼计算机设备,科学网—计算机学习漫谈(10)——一台冯·诺依曼机器 - 陈钊的博文...
  13. 微信打开第三方app
  14. 大学生川菜网页制作教程 学生HTML静态美食菜品网页设计作业成品 简单网页制作代码 学生美食网页作品免费设计
  15. 灭点计算 matlab,基于两个灭点的相机标定
  16. Civil3D二次开发之撤销(Undo\Ctrl+Z)命令
  17. 基于word2vec+TextCNN 实现中文文本分类
  18. (python)生产者消费者模型
  19. Retrofit 2.0 轻松实现多文件/图片上传/Json字符串/表单
  20. 计算机上用户名怎么设置,电脑用户名,详细教您电脑用户名怎么修改

热门文章

  1. 阿里国际站用户增长技术探索与实践
  2. python爬京东延迟加载_python大规模爬取京东
  3. 在微信里接收文件后如何指着文件用咱编的APP打开?
  4. 第一行代码 第三版 第11章网络技术 11.6.1 Retrofit 应用 报错:android.system.ErrnoException: isConnected failed: ECONNRE
  5. 数据结构---树和二叉树03
  6. java poi导出PPT格式
  7. 中国3D打印软件市场现状分析及发展前景预测报告
  8. java 使用poi将PPT转为图片,在线预览PPT
  9. 云呐|加强固定资产设备信息化管理工作
  10. 微信-软件 报警信息