2023年 5月 做题记录

文章详细介绍了树上动态规划(dp)在解决摆渡车问题中的应用,以及如何利用斜率优化来提升效率。同时,讨论了最小割问题,包括如何判断可行边和必须边,并给出了判断方法。此外,还涉及了数表问题和最长递增子序列(LIS)问题的解决方案,以及供给侧改革问题的动态规划策略。最后,文章提到了随机行走问题的树上高斯消元法。
摘要由CSDN通过智能技术生成

共9题.记于 6.1

关键词索引:斜率优化,退流,可行边,必须边,路径相关的二次扫描树上 dp,树上高斯消元.

P5017 [NOIP2018 普及组] 摆渡车

考虑在时间轴上 dp。
f [ i ] f[i] f[i] 表示在 i i i 处开始一次摆渡, i i i 时刻及以前的所有学生等待时间和的最小值。记最后一名学生开始等待的时间为 t m x tmx tmx,则最终答案为 min ⁡ t m x ≤ i ≤ t m x + m f [ i ] \displaystyle \min_{tmx \le i \le tmx+m}f[i] tmxitmx+mminf[i]。因为当时刻大于等于 t m x tmx tmx 时,可以保证所有同学已经上车。
考虑 dp 转移式。枚举上一次上车的时刻 j j j,则在 ( j , i ] (j, i] (j,i] 内的学生需要等待此次摆渡车。记 s u m [ i ] sum[i] sum[i] 表示 i i i 时刻及之前开始等待的学生开始等待的时刻之和, n u m [ i ] num[i] num[i] 表示 i i i 时刻及之前开始等待的学生的个数。有转移式:
f [ i ] = min ⁡ 0 ≤ j ≤ m i n ( 0 , i − m ) f [ j ] + i ∗ ( n u m [ i ] − n u m [ j ] ) − ( s u m [ i ] − s u m [ j ] ) \displaystyle f[i]=\min_{0 \le j \le min(0, i-m)} f[j]+i*(num[i]-num[j])-(sum[i]-sum[j]) f[i]=0jmin(0,im)minf[j]+i(num[i]num[j])(sum[i]sum[j])
发现可以斜率优化,即完成。

关于斜率优化:
对于形如 f [ i ] = m a x    o r    m i n ( f [ j ] ∗ g [ i ] + a [ i ] + b [ j ] ) f[i]={max\;or\;min}(f[j]*g[i]+a[i]+b[j]) f[i]=maxormin(f[j]g[i]+a[i]+b[j]) 转移形式的 dp 方程。其特征是存在一个分别与 i i i j j j 相关的函数相乘的项,考虑如下处理:对于一种可能的转移形如 f [ i ] = f [ j ] ∗ g [ i ] + a [ i ] + b [ j ] f[i]=f[j]*g[i]+a[i]+b[j] f[i]=f[j]g[i]+a[i]+b[j],写成 g [ i ] ∗ f [ j ] + ( a [ i ] − f [ i ] ) = − b [ j ] g[i]*f[j]+(a[i]-f[i])=-b[j] g[i]f[j]+(a[i]f[i])=b[j]。发现如果将 ( f [ j ] , − b [ j ] ) (f[j], -b[j]) (f[j],b[j]) 视作平面上的一个点,则方程可被视作一个一次函数的截距式,其中 g [ i ] g[i] g[i] 为斜率, f [ i ] f[i] f[i] 的取值由截距决定。在意图最大或最小化 f [ i ] f[i] f[i] 的时候,往往会发现在枚举到的 j j j 中,仅有点集突壳对应的 j j j 可能会被选中。对其进行维护。

P3308 [SDOI2014]LIS

先介绍建模方法:
i i i 拆点为 i n [ i ] , o u t [ i ] in[i],out[i] in[i],out[i],建从 i n [ i ] in[i] in[i] o u t [ i ] out[i] out[i] 边权为 b [ i ] b[i] b[i] 的边。求出以每个点结束的 LIS 长度记为数组 f [ ] f[] f[]。对于形如 ( i , j ) (i, j) (i,j),满足 i < j , f [ i ] + 1 = f [ j ] , a [ i ] < a [ j ] i<j,f[i]+1=f[j],a[i]<a[j] i<j,f[i]+1=f[j],a[i]<a[j] 的点对,建 o u t [ i ] out[i] out[i] i n [ j ] in[j] in[j] 边权为 i n f inf inf 的边。引入虚拟源汇点 S , T S,T S,T。对于 f [ i ] = 1 f[i]=1 f[i]=1 的点,建 S S S i n [ i ] in[i] in[i] 边权为 i n f inf inf 的边;对于 f [ i ] = 总序列 L I S f[i]=总序列LIS f[i]=总序列LIS 的点,建 T T T o u t [ i ] out[i] out[i] 边权为 i n f inf inf 的边。

这个图的最小割即为 S S S(最小代价)的答案。

再考虑证明它的正确性:
若存在一条没被割掉的路径,显然对应一种总序列 LIS 的选取方法,并且任意一种总序列 LIS 的选取方式都能在图上找到对应路径。

最后考虑最优字典序方案的构造:
将所有点按 c [ ] c[] c[] 排序,从小到大考虑每个点是否能被包含到最小割集中(本质上是贪心地构造一组最小割集)。对于一个点 i i i,图上的边 e i = ( i → i + n , w ) e_i=(i \rightarrow i+n, w) ei=(ii+n,w) 若可以存在于割集中,将 i i i 计入答案数组,从图上将 e i e_i ei 去掉。
补充1:最小割中的可行边和必须边退流

P3312 [SDOI2014]数表

σ 1 ( n ) = ∑ d ∣ n d \displaystyle \sigma_1(n)=\sum_{d|n}d σ1(n)=dnd

多组询问每次给出 n n n, m m m, a a a,求 ∑ i = 1 n ∑ j = 1 m [ σ 1 ( g c d ( i , j ) ) ≤ a ] σ 1 ( g c d ( i , j ) ) \displaystyle \sum_{i=1}^{n}\sum_{j=1}^{m} [\sigma_1(gcd(i,j)) \le a]\sigma_1(gcd(i,j)) i=1nj=1m[σ1(gcd(i,j))a]σ1(gcd(i,j))

原式 = ∑ d = 1 n [ σ 1 ( d ) ≤ a ] σ 1 ( d ) ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] \displaystyle =\sum_{d=1}^{n} [\sigma_1(d) \le a]\sigma_1(d) \sum_{i=1}^{n}\sum_{j=1}^{m} [gcd(i, j)=d] =d=1n[σ1(d)a]σ1(d)i=1nj=1m[gcd(i,j)=d]

= ∑ d = 1 n [ σ 1 ( d ) ≤ a ] σ 1 ( d ) ∑ i = 1 n d μ ( i ) ⌊ n d i ⌋ ⌊ m d i ⌋ \displaystyle =\sum_{d=1}^{n} [\sigma_1(d) \le a]\sigma_1(d) \sum_{i=1}^{\frac{n}{d}}\mu(i)\lfloor\frac{n}{di}\rfloor\lfloor\frac{m}{di}\rfloor =d=1n[σ1(d)a]σ1(d)i=1dnμ(i)dindim

σ 1 ′ ( n ) = [ σ 1 ( n ) ≤ a ] σ 1 ( n ) \sigma_{1}^{'}(n)=[\sigma_{1}(n) \le a]\sigma_{1}(n) σ1(n)=[σ1(n)a]σ1(n) T = d i T=di T=di

上式 = ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T σ 1 ′ ( d ) μ ( T d ) \displaystyle =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor \sum_{d|T}\sigma_{1}^{'}(d)\mu(\frac{T}{d}) =T=1nTnTmdTσ1(d)μ(dT)

预处理 g ( T ) = ∑ d ∣ T σ 1 ′ ( d ) μ ( T d ) \displaystyle g(T)=\sum_{d|T}\sigma_{1}^{'}(d)\mu(\frac{T}{d}) g(T)=dTσ1(d)μ(dT).单组询问可以 O ( n ) O(\sqrt n) O(n )回答.

对于 a a a 不同, g ( ) g() g()会发生变化.我们考虑将询问离线按 a a a 从小到大排序.顺序扫描加点,发现加入一个新的 i i i 使得 σ 1 ′ ( i ) > 0 \sigma_{1}^{'}(i)>0 σ1(i)>0
时,会对满足 i ∣ j i|j ij g ( j ) g(j) g(j) 造成影响.即 g ( j ) + σ 1 ′ ( i ) ∗ μ ( j u ) → g ( j ) g(j)+\sigma_{1}^{'}(i)*\mu(\frac{j}{u}) \rightarrow g(j) g(j)+σ1(i)μ(uj)g(j)

我们使用支持单点修改区间查询和的数据结构维护 g ( ) g() g(),题目就做完了.

时间复杂度为 O ( n log ⁡ 2 n + n n log ⁡ n ) O(n\log^{2}n + n\sqrt{n}\log n) O(nlog2n+nn logn)

P4126 [AHOI2009]最小割

其实是上接 P3308 [SDOI2014]LIS 中对最小割可行边和必须边的讨论.现在我会对其算法进行自己的解释和讨论.

注:感谢 command_block 题解和万能的 uoj 群友.

可行边指存在于至少一个最小割集中的边.
必须边指包含于任意最小割集中的边.
发现题目的两问分别为判断可行边和判断必须边.
我们现在考虑判断方法.

设最大流得到的某一个(任意一个)残量网络为 G G G

p a r t    1 part\;1 part1 可行边.

对于一条边 e e e,如果它在 G G G 上不是满流(满流指最大流后边权减为 0 0 0, 即被流满了),则将 e e e 的边权 − e p s -eps eps(即减少一个微小值)之后,最大流的大小没有变化;而如果其满流,这样操作最大流肯定会变小.若 e e e 不满流,则假设 e e e 存在于一种最小割集中,将 e e e 的边权 − e p s -eps eps,最小割集的大小会发生变化,而根据最大流等于最小割,最大流也因发生变化,而这于上文的结论不符.这就证明了,存在一种最大流后的残量网络使得 e e e 不满流等价于(当且仅当) e e e 不被包含在任意一个最小割集中.
对于一条边 e = ( u → v , w ) e=(u \rightarrow v, w) e=(uv,w) 在进行最大流后若被流满,则有可能为可行边,需要进一步确定判断.我们考虑若存在一种最大流后的残量网络使得 e e e 流不满,则应该满足可以找到 u → v u \rightarrow v uv 的另一条增广路径使得 v v v 交还给 u u u 一些流量(流经 e e e 的)后, u u u 可以不通过 e e e 将其送到 v v v.对应在当前的残量网络上,我们只需要判断 u u u v v v 是否在同一个强联通分量里即可(请注意,这里的强联通分量指的是由残量网络上不走边权为 0 0 0 的边后求得的强联通分量).

p a r t    2 part\;2 part2 必须边.

必须边集包含于可行边集.我们沿用 p a r t    1 part\;1 part1 中的思路,求出残量网络上不走 0 边后的缩点图 G ′ G^{'} G G ′ G^{'} G 的边集是原图中满流,并且在缩点后不成自环的边,即使用有残余流量边缩点得到的新图再用满流边连接).可以发现, G ′ G^{'} G 上的边就是可行边集.任意一种最小割,应都是若干个 G ′ G^{'} G 中的边组成的,并且 G ′ G^{'} G 中任意一种紧的割都是最小割.
这里先提供一种构造最小割集的方法.将 G ′ G^{'} G 上的点划分成两个联通块,一部分和 s s s 相连,记作 S S S 集,另一部分和 t t t 相连,记作 T T T 集,将 S S S 集和 T T T 集间的边割掉,即构造出了一种最小割.
我们对于 e = ( u → v ) e=(u \rightarrow v) e=(uv),若 v v v 所在的强联通分量与 t t t 所在的强联通分量不同,我们构造 S = { x ∣ x ∈ p a t h s → v } S=\left\{ x|x \in path_{s \rightarrow v} \right\} S={xxpathsv},若 u u u 所在的强联通分量和 s s s 所在的强联通分量不同,我们构造 T = { x ∣ x ∈ p a t h u → t } T=\left\{ x|x \in path_{u \rightarrow t} \right\} T={xxpathut}.这两中情况都可以构造出 e e e 不割的一种最小割集出来,易知 e e e 不是必须边;而剩下的情况,即 s s s u u u 在同一强联通分量并且 v v v t t t 在同一强联通分量,可得知 e e e 一定为必须边.故也可以这样判断必须边:沿着残量网络中的非 0 0 0 边, s s s 可做到达 u u u v v v可以到达 t t t

P3365 改造二叉树

求保证中序排列递增所需要的最小修改节点个数.
考虑在中序排列的序列上 dp 最多可以保留不改的节点个数.设计 f i f_i fi 表示若 i i i 不改,前 i i i 个最多有多少可以不改.有转移 f i = max ⁡ j < i , a i − a j ≥ i − j f j + 1 \displaystyle f_i=\max_{j<i,a_i-a_j \ge i-j} f_j+1 fi=j<i,aiajijmaxfj+1.我们分析条件 a i − a j ≥ i − j a_i-a_j \ge i-j aiajij a i − i ≥ a j − j a_i-i \ge a_j-j aiiajj.故整个序列中最多可以保留不改的节点个数即在新序列 b i = a i − i b_i=a_i-i bi=aii 中最长上升子序列的长度.

P5324 [BJOI2019]删数

需要重新解释“可删”并思考快速求出最小更改次数的方法.
我们考虑枚举元素 a i a_i ai 满足 a i ∈ [ 1 , n ] a_i \in [1, n] ai[1,n],把当前序列中等于 a i a_i ai 的元素在数轴的 a i a_i ai 位置垒到一起,向左推倒覆盖所及的区间.答案即为最后 [ 1 , n ] [1, n] [1,n] 中没有被覆盖的整数的个数.
分析意义,对于任意一种“可删”序列,进行上述操作后会保证 [ 1 , n ] [1, n] [1,n] 中每个整数都被覆盖一次.但由于序列长度为 n n n,故只需保证每个整数都被覆盖即可.然后对于一个“非可删”序列,我们将覆盖中重复或大小在 [ 1 , n ] [1, n] [1,n] 以外的元素变为在 [ 1 , n ] [1, n] [1,n] 中空缺的整数,即构造出了一种最优秀的修改方案.
考虑操作,对于整体 + 1 +1 +1 − 1 -1 1,我们直接左移或右移考察的区间 [ 1 , n ] [1, n] [1,n],对于改变某一元素,在线段树容易维护两者覆盖区间的变化即可.

P6419 [COCI2014-2015#1] Kamp

非常经典的二次扫描树形 dp 题啊.
k k k 个人分布的点集为 K K K.点 u u u 答案显然为 2 S u − max ⁡ v ∈ K ( ∑ e ∈ p a t h u − v w e ) \displaystyle 2S_u-\max_{v \in K}{(\sum_{e \in path_{u-v}}w_e)} 2SuvKmax(epathuvwe).其中 S u S_u Su 表示 k k k 个点到 u u u 的路径覆盖的边的边权和.而式子后面的一部分是选出 u u u k k k 个点其中之一的最长路径.两部分都可以二次扫描解决.
值得总结的一点是,在关于最优化端点出发路径的二次扫描中,从 u u u 转移到 v v v,即从 u u u 作为端点的路径到 v v v 作为端点的路径,存在两种情况.设一条以 u u u 为端点的路径是 p a t h u − x path_{u-x} pathux.当 x x x 包含在 v v v 子树中时, p a t h v − x path_{v-x} pathvx 要去掉 e ( u , v ) e(u, v) e(u,v).否则 p a t h v − x path_{v-x} pathvx 中要加入 e ( u , v ) e(u, v) e(u,v).而通常的处理办法是在第一次和第二次扫描的 dp 数组中记下最优和次优路径,并都保证同一子树内只贡献一条(最优的)路径.记第一次扫描的 dp 数组为 f f f,第二次为 g g g.通过 g u g_u gu f v f_v fv 来推断 g v g_v gv:子树内的路径 f v f_v fv 已经有了最优化结果,考虑直接加入 g v g_v gv 中,再判断出 f u f_u fu 中另一端点不在 v v v 子树内的最优路径用其更新 g v g_v gv

P3732 [HAOI2017]供给侧改革

a i a_i ai 为字符串中的第 i i i 个字符, S i S_i Si 为以 i i i 开头的后缀, L C P ( S i , S j ) LCP(S_i, S_j) LCP(Si,Sj) S i S_i Si S j S_j Sj 的最长公共前缀.

考虑 L C P ( S i , S j ) = k LCP(S_i, S_j)=k LCP(Si,Sj)=k 的条件为 ∀ i ≤ x ≤ i − k + 1 , a x = a x − j + i \forall i \le x \le i-k+1, a_x=a_{x-j+i} ixik+1,ax=axj+i.由于 a i a_i ai 是随机生成的, i , j i,j i,j 确定时, L C P ( S i , S j ) = k LCP(S_i, S_j)=k LCP(Si,Sj)=k 概率为 1 2 k \displaystyle \frac{1}{2^{k}} 2k1.当 k k k 取到 40 40 40,在整个串里存在两后缀的 L C P = k LCP=k LCP=k 的概率约为 n 2 2 40 \displaystyle \frac{n^2}{2^{40}} 240n2,近乎为 0 0 0.我们直接默认任意两串的 L C P ≤ 40 LCP \le 40 LCP40 来做即可.这个概率的估算感觉颇有问题,但只考虑前 40 40 40 位是对的——笔者大概不能严谨证明,可以参阅其他题解...姑且这样吧.

将询问离线下来,挂在右端点上,从左往右扫描字符串.
设扫描到位置 r r r.我们维护 g i = d a t a ( i , r )    ( i < r ) g_i=data(i, r)\;(i<r) gi=data(i,r)(i<r),对于询问 ( l , r ) (l, r) (l,r),答案为 ∑ i = l r − 1 g i \displaystyle \sum_{i=l}^{r-1} g_i i=lr1gi
现在考虑加入位置 r r r 后, g g g 会发生什么变化.枚举 i < r i<r i<r,发现 L C P ( S i , S r ) LCP(S_i,S_r) LCP(Si,Sr) 会被计入 g x    ( x ≤ i ) g_x\;(x\le i) gx(xi) 中.但是枚举 i i i 时间复杂度显然不够优秀.我们利用 L C P ≤ 40 LCP \le 40 LCP40 的结论,考虑枚举 L C P ( i , r ) LCP(i, r) LCP(i,r) 的值 l e n len len.显然我们只需要找到 max ⁡ L C P ( i , r ) = l e n , i < r i \displaystyle \max_{LCP(i, r)=len, i<r}i LCP(i,r)=len,i<rmaxi l e n len len 会被计入 g x    ( x ≤ i ) g_x\;(x\le i) gx(xi).我们更新它们的最大值即可.

如何实现呢?
维护一棵 01    T r i e 01\;Trie 01Trie,扫描到 r r r 时将 S i    ( i < r ) S_i\;(i<r) Si(i<r) 的前 40 40 40 位插入到里面.对于 T r i e Trie Trie 上的节点 u u u,维护最后一次经过过它的后缀编号为 m x u mx_u mxu.在 T r i e Trie Trie 上跑 S r S_r Sr,对于经过的节点 u u u,设其深度是 l e n u len_u lenu,发现 m x u = max ⁡ L C P ( i , r ) ≥ l e n u , i < r i \displaystyle mx_u=\max_{LCP(i, r)\ge len_u, i<r}i mxu=LCP(i,r)lenu,i<rmaxi.然后前缀更新 g i g_i gi 的最大值即可.又发现 g i g_i gi 只有前缀更新最大值的操作,故 g i g_i gi 单调不降,我们用线段树维护 g i g_i gi,可以在更新 g i g_i gi 时二分出第一个需要更新的位置,再做一个区间覆盖即可.

现在到了复杂度分析环节.时间复杂度 O ( 40 n log ⁡ n ) O(40n\log n) O(40nlogn),空间复杂度 O ( 40 n ) O(40n) O(40n).可以(勉强)通过此题.

这个做法借鉴了线段树维护历史版本和(扫描线)的思想.现在做区间的子区间脑子里全是扫描线.

Random Walk

F u F_u Fu 为经过 u u u 的期望次数, d u d_u du u u u 的度数.有转移

F u = { F f a d f a + [ u = S ] + ∑ v F v d v ( u ≠ T ) 1 ( u = T ) F_u= \begin{cases} \frac{F_{fa}}{d_{fa}}+[u=S]+\sum_{v}\frac{F_v}{d_v} &(u\neq T)\\ 1 &(u=T) \end{cases} Fu={dfaFfa+[u=S]+vdvFv1(u=T)(u=T)

发现这是一个高斯消元的形式.现在介绍通过树上 dp 完成 O ( n ) O(n) O(n) 树上高斯消元的方法.
请注意,下面是对于树上高斯消元的介绍,与前面的转移方程无关

设需要求解 F u ( u ∈ 1 , 2 , . . . n ) F_u(u \in {1,2,...n}) Fu(u1,2,...n).有转移方程

F u = k f a F f a + ∑ v k v F v + d F_u=k_{fa}F_{fa}+\sum_{v}k_vF_v+d Fu=kfaFfa+vkvFv+d

我们考虑将 F u F_u Fu 表示成只和 F f a F_{fa} Ffa 和一常数有关的式子: F u = g u F f a + c u \displaystyle F_u=g_uF_{fa}+c_u Fu=guFfa+cu

现在考虑如何求解 g , c g, c g,c

F u = k f a F f a + ∑ v k v F v + d = k f a F f a + ∑ v k v ( g v F u + c v ) + d = k f a F f a + ( ∑ v k v g v ) F u + ∑ v k v c v + d \begin{aligned} F_u &=k_{fa}F_{fa}+\sum_{v}k_vF_v+d \\ &=k_{fa}F_{fa}+\sum_{v}k_v(g_vF_u+c_v)+d \\ &=k_{fa}F_{fa}+(\sum_{v}k_vg_v)F_u+\sum_{v}k_vc_v+d \end{aligned} Fu=kfaFfa+vkvFv+d=kfaFfa+vkv(gvFu+cv)+d=kfaFfa+(vkvgv)Fu+vkvcv+d

( 1 − ∑ v k v g v ) F u = k f a F f a + ∑ v k v c v + d F u = k f a F f a 1 − ∑ v k v g v + ∑ v k v c v + d 1 − ∑ v k v g v \begin{aligned} (1-\sum_{v}k_vg_v)F_u&=k_{fa}F_{fa}+\sum_{v}k_vc_v+d\\ F_u&=\frac{k_{fa}F_{fa}}{1-\sum_{v}k_vg_v}+\frac{\sum_{v}k_vc_v+d}{1-\sum_{v}k_vg_v} \end{aligned} (1vkvgv)FuFu=kfaFfa+vkvcv+d=1vkvgvkfaFfa+1vkvgvvkvcv+d

易发现

g u = k f a 1 − ∑ v k v g v c u = ∑ v k v c v + d 1 − ∑ v k v g v \begin{aligned} g_u&=\frac{k_{fa}}{1-\sum_{v}k_vg_v}\\ c_u&=\frac{\sum_{v}k_vc_v+d}{1-\sum_{v}k_vg_v} \end{aligned} gucu=1vkvgvkfa=1vkvgvvkvcv+d

先做一遍 dfs,将 g , c g, c g,c 数组求出.
在根节点处, g f a = 0 g_{fa}=0 gfa=0,可以直接求出 F r o t F_{rot} Frot 的值.
再做一遍 dfs,将 F F F 数组求出即可.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值