概述
树形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
totleq 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_xleq mid
fx+gx≤mid,则
x
x
x子树内所有点都已经被覆盖,
f
x
←
−
∞
f_xleftarrow -infin
fx←−∞
若
f
x
=
m
i
d
f_x=mid
fx=mid,则
x
x
x一定要选,
f
x
←
−
∞
,
g
x
←
0
,
t
o
t
+
+
f_xleftarrow -infin,g_xleftarrow 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_xleftarrow 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_{vin son_u}f[v][0]
f[u][1]=∑v∈sonuf[v][0]
f
[
u
]
[
0
]
=
∑
v
∈
s
o
n
u
m
a
x
(
f
[
v
]
[
0
]
,
f
[
v
]
[
1
]
)
f[u][0]=sum_{vin son_u}max(f[v][0],f[v][1])
f[u][0]=∑v∈sonumax(f[v][0],f[v][1])
考虑在基环树上怎么做:
法一:强制断边
首先把环找出来
对于环上一对相邻点
(
x
,
y
)
(x,y)
(x,y),根据题意,
x
,
y
x,y
x,y不能同时选
- 强制 x x x不选,此时 y y y可选可不选,断掉边 ( x , y ) (x,y) (x,y)无影响。断边后做树形dp, f [ x ] [ 0 ] f[x][0] f[x][0]即为此情况下的答案
- 强制 y y y不选,此时 x x x可选可不选,断掉边 ( x , y ) (x,y) (x,y)无影响。断边后做树形dp, f [ y ] [ 0 ] f[y][0] f[y][0]即为此情况下的答案
- 最终答案= 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_{vin son_u} f_{v,0},f_{u,1}=prod_{vin son_u} (f_{v,0}times 2+f_{v,1})-1
fu,0=∏v∈sonufv,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_{vin 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}timesprod_{xin son_{fa},xnot=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)(Tsubseteq 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
∑sta2∣∣sta∣∣=∑i=0nCni2i=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}[sin word_i]
f[s]=∑i=1n[s∈wordi]
g
[
S
]
=
∑
s
∈
S
(
−
1
)
∣
∣
s
∣
∣
+
1
f
[
s
]
g[S]=sum_{sin 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}[sin word_i]
f[s]=∑i=1n(−1)∣∣s∣∣+1[s∈wordi]
则
g
[
S
]
=
∑
s
∈
S
f
[
s
]
g[S]=sum_{sin S}f[s]
g[S]=∑s∈Sf[s]
求
f
[
s
]
f[s]
f[s]的复杂度是
O
(
n
⋅
2
3
)
O(ncdot 2^3)
O(n⋅23)(对于每一个单词,枚举其子集)
求
g
[
S
]
g[S]
g[S]的复杂度是
O
(
24
⋅
2
24
)
O(24cdot 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]==jdp[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]∑lf[l]((l+1)3−l3)=dp[i−1]+p[i]∑lf[l](3l2+3l+1)
于是考虑维护
E
l
=
∑
l
f
[
l
]
⋅
l
E_l=sum_lf[l]cdot l
El=∑lf[l]⋅l
E
l
2
=
∑
l
f
[
l
]
⋅
l
2
E_{l^2}=sum_lf[l]cdot l^2
El2=∑lf[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]∑lf[l](l+1)=p[i](El[i−1]+∑lf[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]∑lf[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]=nif[i]+nn−if[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−iif[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]=∑cntpcnt2(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(∑cntpcntcnt+1)∑cntpcntcnt
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<fif[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<fif[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_jgeq 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=1itk
则
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_jcdot k+f[i][j]+s[j]-t_jj
⟺f[i−1][k]+s[k]=tj⋅k+f[i][j]+s[j]−tjj
把
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]−tjj看成
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_1not=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)=∑x2(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=msum 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=1jvk2的最小值
记
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
⟺2sisx+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&1end{bmatrix}=begin{bmatrix}f[n-1]&n-1&1end{bmatrix}timesbegin{bmatrix}10^{len(n)}&0&0\1&1&0\1&1&1end{bmatrix}
[f[n]n1]=[f[n−1]n−11]×⎣
⎡10len(n)11011001⎦
⎤
如果不是
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
ito 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,1a2,1⋮an,1a1,2a2,2⋮an,2⋯⋯⋱⋯a1,ma2,m⋮an,m⎦
⎤∗⎣
⎡b1,1b2,1⋮bm,1b1,2b2,2⋮bm,2⋯⋯⋱⋯b1,nb2,n⋮bm,n⎦
⎤=⎣
⎡c1,1c2,1⋮cn,1c1,2c2,2⋮cn,2⋯⋯⋱⋯c1,nc2,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(1leqk<i,0leq lleq j,h[i]+jgeq 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复健计划——动态规划的全部内容,希望文章能够帮你解决NOIP复健计划——动态规划所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复