凸优化算法学习笔记:决策单调性与 wqs二分

文章目录

前言

学习了凸性相关的算法。
有:决策单调性,wqs二分, 闵可夫斯基和, slope trick。
一般是用来优化dp。
文章写的太长了因此分成两篇发。

决策单调性

单调矩阵,完全单调矩阵,蒙日阵

  • 单调矩阵:每行最小值/最大值的位置单调的矩阵。
  • 完全单调矩阵:若一个矩阵 A A A 满足其所有子矩阵均为单调矩阵,那么称其为完全单调矩阵。

常见的决策单调性问题其实就是在单调矩阵上求一行最小值的问题。一般用 四边形不等式 判定是否具有决策单调性。

  • 蒙日阵:满足 ∀ 1 ≤ i 1 < i 2 ≤ n , 1 ≤ j 1 < j 2 ≤ m \forall 1 \leq i_1 < i_2 \leq n, 1\leq j_1 < j_2 \leq m ∀1i1<i2n,1j1<j2m A i 1 , j 1 + A i 2 , j 2 ≤ A i 1 , j 2 + A i 2 , j 1 A_{i_1, j_1} + A_{i_2, j_2} \leq A_{i_1, j_2} + A_{i_2, j_1} Ai1,j1+Ai2,j2Ai1,j2+Ai2,j1 的矩阵 A A A 被称为 蒙日阵。也称 A A A 满足四边形不等式。其中 A i 1 , j 1 + A i 2 , j 2 ≤ A i 1 , j 2 + A i 2 , j 1 A_{i_1, j_1} + A_{i_2, j_2} \leq A_{i_1, j_2} + A_{i_2, j_1} Ai1,j1+Ai2,j2Ai1,j2+Ai2,j1 中的 ≤ \leq 理解为 优于

有重要结论:蒙日阵是完全单调矩阵

证明:

  1. 判断一个矩阵是否为完全单调矩阵只需要看任意的 2 × 2 2 \times 2 2×2 子矩阵是否为单调矩阵。可以画图理解。
  2. 1 1 1 得:若一个矩阵 A A A 是完全单调矩阵,需满足 ∀ 1 ≤ i 1 < i 2 ≤ n , 1 ≤ j 1 < j 2 ≤ m \forall 1 \leq i_1 < i_2 \leq n, 1 \leq j_1 < j_2 \leq m ∀1i1<i2n,1j1<j2m A i 1 , j 1 ≤ A i 1 , j 2 A_{i_1, j_1} \leq A_{i_1, j_2} Ai1,j1Ai1,j2 A i 1 , j 1 > A i 2 , j 2 且 A i 2 , j 1 > A i 2 , j 2 A_{i_1, j_1} > A_{i_2, j_2}且 A_{i_2, j_1} > A_{i_2, j_2} Ai1,j1>Ai2,j2Ai2,j1>Ai2,j2。反过来讲,若 ∃ 1 ≤ i 1 < i 2 ≤ n , 1 ≤ j 1 < j 2 ≤ m \exists 1 \leq i_1 < i_2 \leq n, 1 \leq j_1 < j_2 \leq m ∃1i1<i2n,1j1<j2m,满足 A i 1 , j 1 > A i 1 , j 2 且 A i 2 , j 1 ≤ A i 2 , j 2 A_{i_1, j_1} > A_{i_1, j_2} 且 A_{i_2, j_1} \leq A_{i_2, j_2} Ai1,j1>Ai1,j2Ai2,j1Ai2,j2,那么 A A A 就不是完全单调矩阵。发现此时 A i 1 , j 1 + A i 2 , j 2 > A i 1 , j 2 + A i 2 , j 1 A_{i_1, j_1} + A_{i_2, j_2} > A_{i_1, j_2} + A_{i_2, j_1} Ai1,j1+Ai2,j2>Ai1,j2+Ai2,j1,与蒙日阵定义矛盾。证必。

这说明了,如果一个矩阵满足四边形不等式,那么它具有决策单调性。

判定一个矩阵为蒙日阵:

方法一:根据定义,证明 ∀ 1 ≤ i 1 < i 2 ≤ n , 1 ≤ j 1 < j 2 ≤ m \forall 1 \leq i_1 < i_2 \leq n, 1\leq j_1 < j_2 \leq m ∀1i1<i2n,1j1<j2m A i 1 , j 1 + A i 2 , j 2 ≤ A i 1 , j 2 + A i 2 , j 1 A_{i_1, j_1} + A_{i_2, j_2} \leq A_{i_1, j_2} + A_{i_2, j_1} Ai1,j1+Ai2,j2Ai1,j2+Ai2,j1
方法二:证明 ∀ 1 ≤ i < n , 1 ≤ j < m \forall 1 \leq i < n, 1 \leq j < m ∀1i<n,1j<m A i , j + A i + 1 , j + 1 ≤ A i , j + 1 + A i + 1 , j A_{i, j} + A_{i + 1, j + 1} \leq A_{i, j + 1} + A_{i + 1, j} Ai,j+Ai+1,j+1Ai,j+1+Ai+1,j。相当于仅考虑任意 2 × 2 2 \times 2 2×2 的子矩形。

对方法二正确性的说明:将定义式变形: A i 2 , j 2 − A i 1 , j 2 − A i 2 , j 1 + A i 1 , j 1 ≤ 0 A_{i_2, j_2} - A_{i_1, j_2} - A_{i_2, j_1} + A_{i_1, j_1} \leq 0 Ai2,j2Ai1,j2Ai2,j1+Ai1,j10,发现这是二维差分的形式,相当于要求 A A A 的二维差分矩阵的任意一个矩形和小于等于 0 0 0。这等价于差分后每一个位置上的数都小于等于 0 0 0

特别说明:如果一个矩阵的左下角或右上角没有意义,可以通过给这些位置赋值为 k i × ∞ k_i \times \infty ki× 的方式让跨过斜对角线的 2 × 2 2 \times 2 2×2 子矩形满足四边形不等式。因此可以只关注另一部分是否满足四边形不等式。

蒙日阵的性质:

A , B A, B A,B 为蒙日阵。

  • A T A^{T} AT 为蒙日阵。
  • A + B A + B A+B 为蒙日阵。
  • λ A ( λ ≥ 0 ) \lambda A(\lambda \geq 0) λA(λ0) 为蒙日阵。
  • A A A 的某一行或某一列加上任意常数 c c c 仍为蒙日阵。

一些蒙日阵的例子:

  • A x , y = m i n ( x , y ) A_{x, y} = min(x, y) Ax,y=min(x,y)
  • A x , y = m a x ( x , y ) A_{x, y} = max(x, y) Ax,y=max(x,y)
  • A x , y = ∑ i = 1 x ∑ j = 1 y d i , j A_{x, y} = \sum_{i = 1}^{x}\sum_{j = 1}^{y}d_{i, j} Ax,y=i=1xj=1ydi,j,其中 d d d 为非负矩阵。
  • A x , y = f ( y − x ) A_{x, y} = f(y - x) Ax,y=f(yx),其中 f ( x ) f(x) f(x) 为上凸函数。

决策单调性优化 d p dp dp

线性 d p dp dp

一般是划分段的 d p dp dp。通常会有代价函数 w l , r w_{l, r} wl,r 表示将 [ l , r ] [l, r] [l,r] 划分成一段的代价。
w l , r w_{l, r} wl,r 看做矩阵第 l l l 行第 r r r 列的数,那么 w w w 可看做一个左下角无意义的矩阵。其满足四边形不等式的意义就是区间代价满足 交叉优于包含

分治(离线)

考虑转移式形如 f i , j = min ⁡ k < j f i − 1 , k + w k , j f_{i, j} = \min\limits_{k < j}f_{i - 1, k} + w_{k, j} fi,j=k<jminfi1,k+wk,j d p dp dp

通常第一维为层数或段数,称这样每一层仅有上一层转移得到的 d p dp dp分层转移。这样的 d p dp dp 并不限制转移顺序,可认为每一层内的转移是离线问题。

设第二维长度为 m m m f i − 1 f_{i - 1} fi1 f i f_{i} fi 的转移可以用一个 m × m m \times m m×m 的矩阵 A A A 表示:
A x , y = { f i − 1 , y + w y , x x ≥ y ∞ x < y A_{x, y} = \left\{\begin{matrix} f_{i - 1, y} +w_{y, x} & x \geq y\\ \infty & x < y \end{matrix}\right. Ax,y={fi1,y+wy,xxyx<y
发现转移矩阵 A A A 就是 w w w 转置后每一列 j j j 加上常数 f i − 1 , j f_{i - 1, j} fi1,j
由蒙日矩阵的性质:若 w w w 满足四边形不等式,那么 A A A 一定是蒙日阵,满足决策单调性。

如何求解:
定义函数 s o l v e ( l , r , q l , q r ) solve(l, r, ql, qr) solve(l,r,ql,qr) 表示决策范围是 [ l , r ] [l, r] [l,r],要给 [ q l , q r ] [ql, qr] [ql,qr] 范围的状态进行转移。
那么每次找到中间状态 m i d = q l + q r 2 mid = \frac{ql + qr}{2} mid=2ql+qr,扫描 [ l , r ] [l, r] [l,r] 找到最优决策点 p p p m i d mid mid 进行转移。然后接着递归 s o l v e ( l , p , q l , m i d − 1 ) solve(l, p, ql, mid - 1) solve(l,p,ql,mid1) s o l v e ( p , r , m i d + 1 , q r ) solve(p, r, mid + 1, qr) solve(p,r,mid+1,qr)

复杂度分析:假设每次求一个决策点的转移值复杂度 O ( 1 ) O(1) O(1),那么一共会递归 O ( log ⁡ n ) O(\log n) O(logn) 层,每层复杂度 O ( n ) O(n) O(n),总复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)
如果第一维的大小为 k k k,那么总复杂度为 O ( n k log ⁡ n ) O(nk \log n) O(nklogn)

局限性:只能离线,如果使用 c d q cdq cdq 会多一个 l o g log log
优点:好写,只要求是 单调矩阵 A i , j A_{i, j} Ai,j 不好计算时可以通过跳转指针增量求得

二分队列(在线)

考虑转移式形如 f i = min ⁡ j < i f j + w j , i f_{i} = \min\limits_{j < i} f_j + w_{j, i} fi=j<iminfj+wj,i d p dp dp:

发现转移顺序只能从小到大,视为在线问题。

与上面类似,转移同样可以写成一个 m × m m \times m m×m 的矩阵:
A x , y = { f y + w y , x x ≥ y ∞ x < y A_{x, y} = \left\{\begin{matrix} f_{y} +w_{y, x} & x \geq y\\ \infty & x < y \end{matrix}\right. Ax,y={fy+wy,xxyx<y

不同点在于这个是在线的每次将一列加一个常数。
但是并不影响蒙日阵的性质,因此如果 w w w 满足四边形不等式那么 A A A 同样具有决策单调性。

如何求解:
对每个点维护当前它的最有决策点。具体的说:开一个队列存储三元组 ( l , r , x ) (l, r, x) (l,r,x),表示当前 [ l , r ] [l, r] [l,r] 状态的最优决策点为 x x x。那么每次拿出队头的 i i i 并用决策点更新它,考虑 l l l 会更新那些状态的决策点:不难发现由于决策单调性因此影响的是一段后缀。因此从后往前合并决策点被更新成 i i i 的连续段,如果更新后缀的端点在一段的中间,就二分找到这个端点然后将这一段分裂。

复杂度分析:不难发现每次最多新开一段,并且一段只会被合并一次,因此合并连续段的复杂度均摊 O ( n ) O(n) O(n)。但是每次在段内二分,因此总复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

局限性:需要矩阵满足 完全单调
优点:离线和在线通用。

SMAWK

不会,先鸽了。

区间 d p dp dp

考虑对于形如 d p l , r = min ⁡ l ≤ k ≤ r d p l , k + d p k + 1 , r + w l , r dp_{l, r} = \min\limits_{l \leq k \leq r}dp_{l, k} + dp_{k + 1, r} +w_{l, r} dpl,r=lkrmindpl,k+dpk+1,r+wl,r 的区间 d p dp dp

结论:
w w w满足四边形不等式 且满足 ∀ l ≤ l ′ ≤ r ′ ≤ r , w l ′ , r ′ ≤ w l , r \forall l \leq l' \leq r' \leq r,w_{l',r'} \leq w_{l,r} llrr,wl,rwl,r(区间单调性),那么转移具有决策单调性。
p i , j p_{i, j} pi,j 表示 d p i , j dp_{i, j} dpi,j 的最优决策点,那么有 p i − 1 , j ≤ p i , j ≤ p i , j + 1 p_{i - 1, j} \leq p_{i, j} \leq p_{i, j + 1} pi1,jpi,jpi,j+1

可以通过记录 p p p 然后缩小枚举范围的方式将复杂度优化到 O ( n 2 ) O(n^2) O(n2)

证明:不会

练习题

LOJ6039

n n n 个物品,每个物品体积为 w i w_i wi,价值为 v i v_i vi
求当背包体积为 1 ∼ k 1 \sim k 1k 时的最大价值。
n ≤ 1 0 6 , w i ≤ 300 , k ≤ 5 × 1 0 4 n \leq 10^6,w_i \leq300, k \leq 5 \times 10^4 n106,wi300,k5×104

分析:
直接做 01 01 01背包复杂度为 O ( n k ) O(nk) O(nk),显然过不了。
注意到物品体积值域较小,启示我们把体积相同的物品一起考虑。
d p c , v dp_{c, v} dpc,v 表示考虑了体积为 1 ∼ c 1 \sim c 1c 的物品,当前背包体积为 v v v 的最大价值。
转移显然把 v % c v\%c v%c 后分组:
d p c , c × i + r = max ⁡ j ≤ i d p c − 1 , c × j + r + f ( c , i − j ) dp_{c, c \times i + r} = \max\limits_{j \leq i}dp_{c - 1, c \times j + r} + f(c, i - j) dpc,c×i+r=jimaxdpc1,c×j+r+f(c,ij)
其中 f ( c , x ) f(c, x) f(c,x) 表示体积为 c c c 的物品价值前 x x x 大的物品的价值之和。
发现这与 d p k , i = max ⁡ j ≤ i d p k − 1 , j + w j , i dp_{k, i} = \max\limits_{j \leq i}dp_{k - 1, j} + w_{j, i} dpk,i=jimaxdpk1,j+wj,i 的形式非常像,只是 w j , i = f ( c , i − j ) w_{j, i} = f(c, i - j) wj,i=f(c,ij)
注意到 f ( c , x ) f(c, x) f(c,x) 是上凸的,因此 w w w 满足四边形不等式,每一组的转移满足决策单调性。
那么将每一组跑一遍决策单调性优化 d p dp dp 即可。
复杂度分析:对于一个 c c c,一共有 c c c 组,每一组有 k c \frac{k}{c} ck 个状态,因此复杂度为 O ( c × k c × log ⁡ k c ) = O ( k × log ⁡ k c ) O(c \times \frac{k}{c} \times \log\frac{k}{c}) = O(k \times \log \frac{k}{c}) O(c×ck×logck)=O(k×logck)。总复杂度为 O ( ∑ c ≤ m a x w k × log ⁡ k c ) O(\sum\limits_{c \leq max_w}k \times \log \frac{k}{c}) O(cmaxwk×logck),卡常可过。

w q s wqs wqs 二分(蒙日阵最短路)

算法

考虑转移式形如 f i , j = min ⁡ k < j f i − 1 , k + w k , j f_{i, j} = \min\limits_{k < j}f_{i - 1, k} + w_{k, j} fi,j=k<jminfi1,k+wk,j d p dp dp
刚才我们说,这是一类离线问题,如果 w w w 是蒙日阵,假设第一维大小为 k k k,第二维大小为 n n n,那么可以再 O ( n k log ⁡ n ) O(nk\log n) O(nklogn) 的复杂度求解。

但是如果第一维很大,复杂度就会爆炸。
但是如果最后只需要回答 f k , n f_{k, n} fk,n,其中 k k k 是固定的,那么可以通过 w q s wqs wqs 二分优化复杂度。
通常这类问题的标志是: 恰好分成 k k k

做法
一. 转化成恰好走 k k k 条边的最短路问题

观察上述转移式,发现可以把 f i , j f_{i, j} fi,j 的含义理解成 从起点出发,经过了恰好 i i i 条边,到达了 j j j 号点 的最短路。
其中 i → j i \to j ij 的边权为 w i , j w_{i, j} wi,j,当 i > j i > j i>j 时, w i , j = ∞ w_{i, j} = \infty wi,j=
实际上这张图的邻接矩阵就是 w w w它是一个蒙日阵
那么答案就是从起点出发,恰好走 k k k 条边到达 n n n 的最短路。

二. 证明凸性

g ( k ) = f k , n g(k) = f_{k, n} g(k)=fk,n。那么有结论:当 w w w 为蒙日阵时, g ( k ) g(k) g(k) 是关于 k k k 的下凸函数。(如果取 m a x max max 就是上凸函数)

证明:
g ( k ) g(k) g(k) 为下凸函数等价于 ∀ k ∈ [ 2 , n − 1 ] \forall k \in[2, n - 1] k[2,n1] g ( k ) − g ( k − 1 ) ≤ g ( k + 1 ) − g ( k ) g(k) - g(k - 1) \leq g(k + 1) - g(k) g(k)g(k1)g(k+1)g(k)

假设能找到两条长度为 k k k 的路径 g 1 ′ ( k ) g'_1(k) g1(k) g 2 ′ ( k ) g_2'(k) g2(k) 满足 g 1 ′ ( k ) + g 2 ′ ( k ) ≤ g ( k − 1 ) + g ( k + 1 ) g_1'(k) + g_2'(k) \leq g(k - 1) + g(k + 1) g1(k)+g2(k)g(k1)+g(k+1)
那么有 2 g ( k ) ≤ g 1 ′ ( k ) + g 2 ′ ( k ) ≤ g ( k − 1 ) + g ( k + 1 ) 2g(k) \leq g'_1(k) + g'_2(k) \leq g(k - 1) + g(k + 1) 2g(k)g1(k)+g2(k)g(k1)+g(k+1)。就可以证明原命题了。

假设 g ( k − 1 ) g(k - 1) g(k1) g ( k + 1 ) g(k + 1) g(k+1) 的路径分别为 A , B A,B A,B,用 a , b a, b a,b 表示两条路径上的点。
那么 A , B A,B A,B 是有序的,将两条路径的点按照编号从小到大归并到一起,形成的字符串如下:
a a b b a b . . . a a b aabbab...aab aabbab...aab。其中 a a a 的数量比 b b b 多两个。
考虑找到一条分界线,满足分界线左边 a a a 恰好比 b b b 多一个,且分界线左右相邻的都是 a a a
那么如果将分别线左边的 a a a 和分界线右边的 b b b 拼接成一条路径,剩下的点拼成一条路径,不难发现两条路径的长度都为 k k k
在这里插入图片描述

并且两条路径的边权和与原来相比唯一改变的就是跨过分界线的两条边:b…aa…b 原来是 bb + aa 现在是 ba + ab。这个由 四边形不等式 可以得到现在两条路径的边权和更小。

这样就相当于找到了两条 g 1 ( k ) g_1(k) g1(k) g 2 ( k ) g_2(k) g2(k)

那么一定能找到这样的分界线吗?
不妨将 b b b 看做 − 1 -1 1 a a a 看做 1 1 1。然后可以画出一条从 ( 0 , 0 ) (0, 0) (0,0) 跑到 ( 2 k , 2 ) (2k, 2) (2k,2) 的折线。那么这样的分界线的意义就是折线越过 y = 1 y = 1 y=1 的横坐标。容易得到这样分界线一定存在。

三. w q s wqs wqs 二分

证明了 g ( k ) g(k) g(k) 是下凸函数,如何求解某个点值 ( x , g ( x ) ) (x, g(x)) (x,g(x)) 呢?

考虑二分一个斜率 k k k,求斜率为 k k k 的直线与凸包的切点。如果这个切点横坐标大于 x x x,说明二分的斜率偏大,否则斜率偏小。不断缩小 k k k 的范围直到直线与凸包相切在 x x x 就成功了。如果凸包和直线相切的是一段,也就是有多个切点,要规定此时选择最大或最小的那个。

怎么求一条斜率为 k k k 的直线和凸包的切点呢?
设直线为 y = k x + b y = kx + b y=kx+b 时与凸包相交,那么当直线与凸包相切时 b b b 最小。
f ( x ) = k x + b ⇒ b = f ( x ) − k x f(x) = kx + b \Rightarrow b = f(x) - kx f(x)=kx+bb=f(x)kx
也就是说,如果让每走一步需要减去一个额外代价 k k k,此时不考虑步数,求出走到 n n n 时花费的最小代价就是最小的 b b b。此时走的步数 p p p 就是切点横坐标。

不难发现每走一步减去一个额外代价 k k k 相当于让蒙日阵整体减去一个常数,那么还是蒙日阵。问题就变成了不考虑步数的在线问题。仍然可以用 二分队列 优化转移。

复杂度 O ( n log ⁡ n log ⁡ V ) O(n \log n \log V) O(nlognlogV)

进一步拓展
实际上 w q s wqs wqs 二分的应用并不局限于可以转化为蒙日阵最短路的问题。
只要看到题目上要求 某些变量的大小恰好为 k k k,并且能够证明或者感受 答案关于这个变量是凸函数,那么就可以用 w q s wqs wqs 二分解决。

因此 w q s wqs wqs 二分与决策单调性的关系可以简单用一句话概括:
具有决策单调性一定可以用 w q s wqs wqs 二分,但是能用 w q s wqs wqs 二分不一定有决策单调性

需要注意:
w q s wqs wqs 二分只能求解对于 某个 给定的 k k k。对一个特定的 k k k 求答案的复杂度时 O ( n log ⁡ n log ⁡ V ) O(n \log n \log V) O(nlognlogV) 的,当需要对所有 k k k 都求答案时, w q s wqs wqs 二分就无法解决。

w q s wqs wqs 二分构造方案
咕咕咕。

练习题

P2619 [国家集训队] Tree I

给你一张 V V V 个点, E E E 条边的无向连通图,每条边是黑色或白色。求一棵最小权的恰好有 k k k 条白色边的生成树。

1 ≤ V ≤ 5 × 1 0 4 1 \leq V \leq 5 \times 10^4 1V5×104 1 ≤ k ≤ E ≤ 1 0 5 1 \leq k \leq E \leq 10^5 1kE105

分析:
f ( k ) f(k) f(k) 表示恰好有 k k k 条白色边的最小生成树。感性猜测 f ( k ) f(k) f(k) 关于 k k k 下凸,因此直接 w q s wqs wqs 二分。每次二分一个斜率 t t t,相当于所有白色边的边权减去 t t t,然后跑一边 k r u s k a l kruskal kruskal 算法。需要注意要保证多个切点时切在最左边,因此每次排序如果一条白边和黑边边权相同那么把黑边排在前面。

P6246 [IOI 2000] 邮局 加强版 加强版

数轴上有 n n n 个点,第 i i i 个点的位置为 a i a_i ai。你需要建立 m m m 个邮局,每个点的代价为它距离最近的邮局的距离。求所有点的最小代价和。

1 ≤ m ≤ n ≤ 5 × 1 0 5 1 \leq m \leq n \leq 5 \times 10^5 1mn5×105 0 ≤ a i ≤ 2 × 1 0 6 0 \leq a_i \leq 2 \times 10^6 0ai2×106

分析:
由于要求 m i n min min m i n min min,因此可以通过钦定每个点去哪个邮局 来计算代价,最后一定能转移出最优的。
对于一个邮局而言,显然前往它的点是一段区间。因此有一个暴力的 d p dp dp
d p i , j dp_{i, j} dpi,j 表示前 i i i 个点划分成 j j j 段,每一段放置一个邮局表示这一段点前往的邮局的最小花费。那么不难发现邮局的位置应该是这一段点的中位数,一段的花费可以 O ( 1 ) O(1) O(1) 计算。直接 d p dp dp 的复杂度为 O ( n 2 m ) O(n^2m) O(n2m)

然后是发现了这是 离线的最优段划分 问题。猜测满足四边形不等式,可以用决策单调性优化。
那么复杂度可以优化到 O ( n m log ⁡ n ) O(nm \log n) O(nmlogn)
注意到是 恰好 m m m,并且满足蒙日阵,等价于蒙日阵最短路,答案具有凸性,可以 w q s wqs wqs 二分。
二分斜率 k k k,那么每开一段需要减 k k k,记录最优方案下开的段数以及花费即可。每次 d p dp dp 可以用 二分队列 优化。
复杂度 O ( n log ⁡ n log ⁡ V ) O(n \log n \log V) O(nlognlogV)
CODE:

// wqs 二分 + 在线决策单调性 
#include<bits/stdc++.h>
#define MP make_pair
using namespace std;
typedef long long LL;
typedef pair< LL, int > PII;
const int N = 5e5 + 10;
int n, m;
LL a[N], s[N];
PII f[N];
struct seg {int L, R, x;
};
int l, r;
seg Stk[N];
LL w(int l, int r) {int mid = (l + r >> 1);return s[r] - s[mid] - (r - mid) * a[mid] + a[mid] * (mid - l + 1) - (s[mid] - s[l - 1]);
}
PII g(int x, int i, int c) {return MP(f[x].first + w(x + 1, i) - c, f[x].second + 1);	
}
void check(int c) {l = r = 1;Stk[l] = (seg) {1, n, 0};for(int i = 1; i <= n; i ++ ) {int x = Stk[l].x;f[i] = g(x, i, c);Stk[l].L ++; if(Stk[l].L > Stk[l].R) l ++;int ll = n + 1, rr = n;while(r >= l && g(i, Stk[r].L, c) < g(Stk[r].x, Stk[r].L, c)) {ll = Stk[r].L;r --;}if(r >= l) {int lt = Stk[r].L, rt = Stk[r].R, mid, res = -1;while(lt <= rt) {mid = (lt + rt >> 1);if(g(i, mid, c) < g(Stk[r].x, mid, c)) res = mid, rt = mid - 1;else lt = mid + 1;}if(res != -1) {ll = res;Stk[r].R = res - 1;}}if(ll <= rr) Stk[++ r] = (seg) {ll, rr, i};}
}
int main() {scanf("%d%d", &n, &m);for(int i = 1; i <= n; i ++ ) scanf("%lld", &a[i]);sort(a + 1, a + n + 1);for(int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i];int l = -1e9, r = 1e9, mid, res;check(-4);while(l <= r) {mid = (l + r >> 1);check(mid);if(f[n].second > m) r = mid - 1;else if(f[n].second == m) {printf("%lld\n", f[n].first + 1LL * m * mid); return 0;}else res = mid, l = mid + 1;}check(res);printf("%lld\n", f[n].first + 1LL * m * res);return 0;
}

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

给你一棵 n n n 个点的树,每条边有边权 v i v_i vi。若 v i < 0 v_i < 0 vi<0,表示经过这条边需要花费 v i v_i vi 的代价。若 v i > 0 v_i > 0 vi>0,表示经过这条边能获得 v i v_i vi 的收益。你可以任意选择 K K K 条边并将它们删掉,然后加入 K K K v i = 0 v_i = 0 vi=0 的边得到一棵新树。接着你可以选择两个点 p , q p, q p,q 并从 p p p 走到 q q q。求出可能的 收益 - 花费 最大是多少。

1 ≤ n ≤ 3 × 1 0 5 1 \leq n \leq 3 \times 10^5 1n3×105 0 ≤ K ≤ 3 × 1 0 5 0 \leq K \leq 3\times 10^5 0K3×105 K < n K < n K<n ∣ v i ∣ ≤ 1 0 6 |v_i| \leq 10^6 vi106

分析:
假设我们已经确定了删除的 K K K 条边,考虑这时最大的 收益 - 花费 是多少。
发现会形成 K + 1 K + 1 K+1 个连通块,那么每个连通块的最长简单路径之和就是答案。
可以证明答案不会超过这个值,也可以构造加的边取到这个值。

发现这 K + 1 K + 1 K+1 条简单路径总是不交的。那么反过来想,任意取 K + 1 K + 1 K+1 条两两不交的简单路径,一定存在一种删边方式把它们划分到不同的连通块里。

这样能说明原问题的答案就是 在树上选出 K + 1 K + 1 K+1 条不交路径,路径之和的最大值
可以树背包:
f i , j f_{i, j} fi,j 表示 以 i i i 为根的子树里选了 j j j 条不交路径,没有一条 半路径 延伸上来的最大值。
g i , j g_{i, j} gi,j 则表示有一条半路径延伸上来。
那么转移时考虑将两半拼起来,并树背包转移即可。复杂度 O ( n 2 ) O(n^2) O(n2)

注意到要求 恰好选出 K + 1 K + 1 K+1 条路径,考虑答案是否关于 K K K 存在凸性。
不难发现 K K K 越大答案越大,因为可以一条路径可以只有一个点。当 K K K 变大时答案的增量越来越小,因为肯定是先选出价值高的路径。
所以感性证明了答案关于 K K K 上凸。
那么直接 w q s wqs wqs 二分即可,每次新选中一条路径要减去斜率。
时间复杂度 O ( n log ⁡ V ) O(n \log V) O(nlogV)

CODE:

// wqs 二分 + 树形 dp
// 相当于求划分若干条不交链的最大权值和 
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
typedef long long LL;
int n, K;
LL sum[N]; // 到根的路径和 
struct edge {int v, last;LL w;
}E[N * 2];
struct G {LL v; int c;friend bool operator < (G x, G y) {return ((x.v < y.v) || (x.v == y.v && x.c > y.c));}friend G operator + (G x, G y) {G z = (G) {x.v + y.v, x.c + y.c};return z;}
};
int head[N], tot;
void add(int u, int v, LL w) {E[++ tot] = (edge) {v, head[u], w};head[u] = tot;
}
void dfs0(int x, int fa) {for(int i = head[x]; i; i = E[i].last) {int v = E[i].v; LL w = E[i].w;if(v == fa) continue;sum[v] = sum[x] + w;dfs0(v, x);}
}
G f[N], g[N], h[N]; // f[x] 没有半链延伸, g[x] 已经拼接过了, h[x] 有一条半链延伸上来了 
void dfs1(int x, int fa, LL cost) {f[x] = (G) {0, 0}; g[x] = (G) {-cost, 1};h[x] = (G) {sum[x], 0};for(int i = head[x]; i; i = E[i].last) {int v = E[i].v;if(v == fa) continue;dfs1(v, x, cost);g[x] = g[x] + max(f[v], g[v]);g[x] = max(g[x], (G) {h[x].v + h[v].v - 2LL * sum[x] - cost, h[x].c + h[v].c + 1});h[x] = max(h[x] + max(g[v], f[v]), h[v] + f[x]);f[x] = f[x] + max(f[v], g[v]);}
}
void check(LL x) { // 新开一条路径的花费为 x dfs1(1, 0, x);
}
int main() {scanf("%d%d", &n, &K); K ++;for(int i = 1; i < n; i ++ ) {int u, v; LL w;scanf("%d%d%lld", &u, &v, &w);add(u, v, w); add(v, u, w);}dfs0(1, 0);LL l = -3e11, r = 3e11, mid, res = 0;while(l <= r) {mid = (l + r >> 1);check(mid);G ans = max(f[1], g[1]);if(ans.c == K) {printf("%lld\n", ans.v + mid * K); return 0;}else if(ans.c > K) l = mid + 1LL;else res = mid, r = mid - 1LL;}check(res);G ans = max(f[1], g[1]);printf("%lld\n", ans.v + 1LL * K * res);return 0;
}

[ARC168E] Subsegments with Large Sums

给定长度为 n n n 的数列 { a i } \{a_i\} {ai} 和两个参数 k , s k, s k,s,将 { a i } \{a_i\} {ai} 划分成 k k k 段,最大化和 ≥ s \geq s s 的段数。

1 ≤ k ≤ n ≤ 250000 1 \leq k \leq n \leq 250000 1kn250000 1 ≤ A i ≤ 1 0 9 1 \leq A_i \leq 10^9 1Ai109 1 ≤ s ≤ 1 0 15 1 \leq s \leq 10^{15} 1s1015

分析:
要恰好分成 k k k 段,考虑 w q s wqs wqs 二分。设 f ( k ) f(k) f(k) 表示恰好分成 k k k 段的答案,猜 f ( k ) f(k) f(k) 关于 k k k 上凸。
但是仔细想就会发现问题,因为可以把和 < s < s <s 的段分成两段,增加了段数但是答案不变,因此 f ( k ) f(k) f(k) 关于 k k k 并不是凸的。

枚举答案 t t t,然后 c h e c k check check 能否有 ≥ t \geq t t 段的和 ≥ s \geq s s。不难发现这是满足单调性的,因为可以二分答案。
那么问题变成了如何 c h e c k check check 是否存在一种划分,满足划分的 k k k 段中至少有 t t t 段的和 ≥ s \geq s s
假设已经确定了这 t t t 段,那么只需要这 t t t 段外的位置数 ≥ k − t \geq k - t kt 就合法,如果不满足就一定不合法。因为每段最少需要有一个元素。
假设此时这 t t t 段的长度之和为 g ( t ) g(t) g(t),只需要 n − g ( t ) ≥ k − t n - g(t) \geq k - t ng(t)kt 即可说明 t t t 合法。那么只需要我们求出最小的 g ( t ) g(t) g(t) 即可。

怎么求 g ( t ) g(t) g(t) 呢?
考虑一个暴力 d p dp dp d p i , j dp_{i, j} dpi,j 表示考虑前 j j j 个位置,当前选出了 i i i 个 和 ≥ s \geq s s 的段,这些段长度之和的最小值。
那么转移有:
d p i , j ← d p i , j − 1 dp_{i, j} \gets dp_{i, j - 1} dpi,jdpi,j1
d p i , j ← d p i − 1 , l s t j − 1 dp_{i, j} \gets dp_{i - 1, lst_j - 1} dpi,jdpi1,lstj1
其中 l s t j lst_j lstj 表示最大的 x x x 满足 [ x , j ] [x, j] [x,j] 的和 ≥ s \geq s s
那么 g ( t ) = d p t , n g(t) = dp_{t, n} g(t)=dpt,n

这样复杂度 O ( n 2 ) O(n^2) O(n2)。但是考虑要求的是 恰好 t t t,考虑 w q s wqs wqs 二分。
不难发现此时 g ( t ) g(t) g(t) 关于 t t t 是上凸的,感性理解就是肯定先选长度较小的合法段,再选长度较大的段。
因此 w q s wqs wqs 二分就是对的。那么外层二分答案,内层 w q s wqs wqs 二分,每次 d p dp dp 复杂度 O ( n ) O(n) O(n),总复杂度就是 O ( n log ⁡ n log ⁡ V ) O(n \log n \log V) O(nlognlogV)
CODE:

// f(x) 表示分成 x 段的最大合法段数, f(x) 不是凸的
// f(x) 表示分出 x 段合法段的最小代价,f(x) 是凸的。 合法的 x 就是一段前缀
// 二分,然后wqs二分求出点值check 
#include<bits/stdc++.h>
#define MP make_pair
using namespace std;
const int N = 250010;
typedef long long LL;
typedef pair< LL, int > PII;
int n, pre[N], K;
LL a[N], s, sum[N];
PII f[N];
void calc(int k) {f[0] = MP(0LL, 0);for(int i = 1; i <= n; i ++ ) {f[i] = f[i - 1];if(pre[i]) f[i] = min(f[i], MP(f[pre[i] - 1].first + i - pre[i] - k, f[pre[i] - 1].second + 1));}
}
LL F(int x) { // 求 x 的点值 int l = 1, r = n, mid, res;while(l <= r) {mid = (l + r >> 1);calc(mid);if(f[n].second == x) {return f[n].first + 1LL * x * mid;}else if(f[n].second < x) res = mid, l = mid + 1;else r = mid - 1;}calc(res);return f[n].first + 1LL * res * x;
}
int main() {scanf("%d%d%lld", &n, &K, &s);for(int i = 1; i <= n; i ++ ) {scanf("%lld", &a[i]);sum[i] = sum[i - 1] + a[i];}int p = 1;for(int i = 1; i <= n; i ++ ) {while(p <= i && sum[i] - sum[p - 1] >= s) {p ++;}pre[i] = p - 1;}int l = 0, r = K, mid, res;while(l <= r) {mid = (l + r >> 1);if(F(mid) <= n - K) res = mid, l = mid + 1;else r = mid - 1;}cout << res << endl;return 0;
}

P5896 [IOI 2016] aliens

给你一个大小为 m × m m \times m m×m 的正方形,上面有 n n n 个点,你需要选出最多 k k k 个正方形使得这 k k k 个正方形的对角线与主对角线重合,并且这 k k k 个正方形能够覆盖所有的点,同时要求正方形的 面积并 最小。

1 ≤ k ≤ n ≤ 1 0 5 1 \leq k \leq n \leq 10^5 1kn105 1 ≤ m ≤ 1 0 6 1 \leq m \leq 10^6 1m106

分析:
由于选出正方形的对角线与主对角线重合,因此我们直接在主对角线上每次选出一段作为某个正方形的对角线。
有两个问题:

  1. 覆盖所有点的限制怎么刻画
  2. 怎么求 面积并

对于第一个问题,发现一个点 ( x , y ) (x, y) (x,y) 能被覆盖到的条件是对角线上选出一段 [ l , r ] [l, r] [l,r] 包含 [ m i n ( x , y ) , m a x ( x , y ) ] [min(x, y), max(x, y)] [min(x,y),max(x,y)]
那么我们可以把点的限制转化为线段覆盖的问题,形如 [ l i , r i ] [l_i, r_i] [li,ri] 至少被某条线段覆盖。
然后是发现如果有限制相包含的情况可以删掉较短的那个,因为满足了较长的限制一定满足较短的。这样所有限制线段都是不交的,可以看作 l , r l,r l,r 分别单增。
把所有限制按照 l l l r r r 从小到大排序。那么每个选中的线段一定覆盖了一个区间的限制线段,假设覆盖了 [ L , R ] [L, R] [L,R] 的限制,显然这一段取 [ l L , r R ] [l_L, r_R] [lL,rR] 是最优的。

对于第二个问题,由于最优方案下我们选中的矩形不可能有包含情况,因此每个选中矩形的面积减去上一个它和上一个相邻的矩形的面积交就是它对答案的贡献。证明可以画图理解。

那么就可以 d p dp dp
d p i , j dp_{i, j} dpi,j 表示考虑了前 j j j 个限制,并且选中了 i i i 段使这 j j j 个限制至少被一条线段包含的最小代价。
怎么转移呢?

d p i , j ← d p i − 1 , k + w k + 1 , j dp_{i, j} \gets dp_{i - 1, k} + w_{k + 1, j} dpi,jdpi1,k+wk+1,j

w i , j = ( r j − l i + 1 ) 2 − ( r i − 1 − l i + 1 ) 2 w_{i, j} = (r_{j} - l_{i} + 1)^2 - (r_{i -1} - l_{i} + 1)^2 wi,j=(rjli+1)2(ri1li+1)2

但是这样转移当没有去掉矩形包含的情况。
其实不用考虑,因为如果存在矩形包含按照这种方式转移只会变得更劣,更不可能成为答案了。

接着发现这是一个典型的 离线最优段划分问题 w w w 满足四边形不等式,因此转移具有决策单调性。
w q s wqs wqs 二分后用 二分队列 优化 d p dp dp,复杂度 O ( n log ⁡ n log ⁡ V ) O(n \log n \log V) O(nlognlogV)
好像 w q s wqs wqs 二分后可以用斜率优化去掉 log ⁡ n \log n logn,但是我没写。

CODE:

// wqs 二分之后决策单调性 
#include<bits/stdc++.h>
#define MP make_pair
using namespace std;
typedef long long LL;
typedef pair< LL, int > PII;
const int N = 1e5 + 10;
int n, m, K, tot;
int R[N], C[N];
PII dp[N];
struct seg {int l, r;
}s[N], h[N];
bool cmp(seg x, seg y) {return ((x.l < y.l) || (x.l == y.l && x.r > y.r));
}
inline LL calc(int x, int y) {x ++;LL S = 1LL * (h[y].r - h[x].l + 1) * (h[y].r - h[x].l + 1);LL ts = (h[x].l > h[x - 1].r ? 0 : 1LL * (h[x - 1].r - h[x].l + 1) * (h[x - 1].r - h[x].l + 1));return S - ts;
}
struct range {int l, r, x;
}stk[N];
int l, r;
inline PII get(int x, int i, LL c) {return MP(dp[x].first + calc(x, i) - c, dp[x].second + 1);
}
void solve(LL c) { // 每开一段 -cl = r = 1; dp[0] = MP(0, 0);stk[l] = (range) {1, tot, 0};for(int i = 1; i <= tot; i ++ ) {int x = stk[l].x;dp[i] = get(x, i, c);stk[l].l ++; if(stk[l].l > stk[l].r) l ++;int lp = n + 1, rp = 0;while(r >= l && get(i, stk[r].l, c) < get(stk[r].x, stk[r].l, c)) {lp = min(lp, stk[r].l); rp = max(rp, stk[r].r);r --;}if(r >= l) { // 二分 int lt = stk[r].l, rt = stk[r].r, mid, res = -1;while(lt <= rt) {mid = (lt + rt >> 1);if(get(i, mid, c) < get(stk[r].x, mid, c)) res = mid, rt = mid - 1;else lt = mid + 1;}if(res != -1) {lp = res; rp = max(rp, stk[r].r); stk[r].r = res - 1;}}if(rp >= lp) stk[++ r] = (range) {lp, rp, i};}
}
int main() {scanf("%d%d%d", &n, &m, &K);for(int i = 1; i <= n; i ++ ) {scanf("%d%d", &R[i], &C[i]);R[i] ++; C[i] ++; s[i] = (seg) {min(R[i], C[i]), max(R[i], C[i])};}sort(s + 1, s + n + 1, cmp);int mxr = 0;for(int i = 1; i <= n; i ++ ) {if(s[i].r <= mxr) continue;h[++ tot] = s[i];mxr = s[i].r;}K = min(K, tot);LL l = -1e12, r = 0, mid, res;while(l <= r) {mid = (l + r >> 1);solve(mid);if(dp[tot].second == K) {printf("%lld\n", dp[tot].first + 1LL * K * mid); return 0;}else if(dp[tot].second < K) res = mid, l = mid + 1;else r = mid - 1;}solve(res);printf("%lld\n", dp[tot].first + 1LL * K * res);return 0; 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/33768.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于YOLOv8深度学习的PCB缺陷检测识别系统【python源码+GUI界面+数据集+训练代码】

目录 一、界面功能展示 二、前言摘要 三、GUI界面演示 &#xff08;一&#xff09;用户加载自定义模型 &#xff08;二&#xff09;单张图像检测 &#xff08;三&#xff09;检测图像文件夹 &#xff08;四&#xff09;检测视频 &#xff08;五&#xff09;保存 四、模…

Matlab 多项式拟合点法线(二维)

文章目录 一、简介二、实现代码三、实现效果一、简介 这个思路其实很简单,假设我们有一组曲线点,我们可以对其拟合曲线并计算其导数来获取每个点的法向量,当然这一思路也可以扩展至三维。具体过程如下所示: 二、实现代码 %% *********

Cesium 入门教程(基于 vue3)

目录 Cesium 介绍&#xff1a; 下载 Cesium&#xff0c;2种路径: 下载成功后&#xff0c;创建 vue3 项目&#xff1a; 编写内容 一个“纯”地球 添加图层 坐标系及其数值转换 相机位置及动态交互 添加物体和3维建筑物 Cesium 介绍&#xff1a; Cesium 是一个开源的 JavaScript …

力扣——合并K个排序链表

题目链接&#xff1a; 链接 题目描述&#xff1a; 思路&#xff1a; 同步合并 已知顺序排列&#xff0c;每个链表的node比较再加进结果&#xff0c;用优先队列方便比较node&#xff0c;可以先把每个链表的头结点加进队列&#xff0c;然后队列头出&#xff0c;出来的头还有n…

可复用表格组件设计与实现:分页、排序、筛选全功能解析

文章目录 一、组件设计思路1.1 功能需求分析1.2 技术选型 二、组件架构设计2.1 组件结构2.2 数据流设计 三、核心代码实现3.1 基础表格组件3.2 状态管理 四、功能模块实现4.1 分页组件4.2 排序控制4.3 筛选控制 五、性能优化方案5.1 虚拟滚动5.2 防抖筛选 六、完整测试方案6.1 …

Unity屏幕适配——立项时设置

项目类型&#xff1a;2D游戏、竖屏、URP 其他类型&#xff0c;部分原理类似。 1、确定设计分辨率&#xff1a;750*1334 为什么是它&#xff1f; 因为它是 iphone8 的尺寸&#xff0c;宽高比适中。 方便后续适配到真机的 “更长屏” 或 “更宽屏” 2、在场景…

PawSQL for TDSQL:腾讯云TDSQL数据库性能优化全攻略

TDSQL 作为腾讯云推出的分布式数据库&#xff0c;凭借其高扩展性、高可用性和高性能等优势&#xff0c;广泛应用于金融、互联网、政务等领域。随着业务的不断增长和数据量的爆炸式增长&#xff0c;如何优化 TDSQL 数据库的性能&#xff0c;成为众多企业和开发者面临的挑战。本文…

机器学习(七)

一&#xff0c;监督学习和无监督学习聚类的数据集比较&#xff1a; 监督学习&#xff1a; 数据集包括输入的数据和与之对应的标签 无监督学习&#xff1a; 数据集仅含有输入的数据&#xff0c;要求算法自己通过所给的数据集来确定决策边界 二&#xff0c;聚类(Clustering): 聚…

海鲜水产行业wordpress外贸主题

模板采用清新的海洋风格设计&#xff0c;完美契合水产和海鲜行业的特点&#xff0c;让您的网站在众多竞争者中脱颖而出。 高质量的图片展示区域&#xff0c;让您可以展示新鲜捕捞的海鲜产品&#xff0c;吸引客户的注意力。 多功能性&#xff0c;满足业务需求&#xff1a; 模…

调优案例一:堆空间扩容提升吞吐量实战记录

&#x1f4dd; 调优案例一&#xff1a;堆空间扩容提升吞吐量实战记录 &#x1f527; 调优策略&#xff1a;堆空间扩容三部曲 # 原配置&#xff08;30MB堆空间&#xff09; export CATALINA_OPTS"$CATALINA_OPTS -Xms30m -Xmx30m"# 新配置&#xff08;扩容至120MB&am…

【大模型系列】llama.cpp本地运行大模型

上一篇链接: 【大模型系列】使用ollama本地运行千问2.5模型 我们讲了ollama本地运行大模型&#xff0c;这里我们介绍另一种本地运行大模型的方法&#xff1a;llamacpp 软件下载 下载地址&#xff1a;https://github.com/ggml-org/llama.cpp/releases 下载cpu版本的llamacpp&a…

maven之自定义插件

写在前面 在使用maven肯定是离不开插件的&#xff0c;比如执行mvn clean或者时mvn compile其实运行的就是绑定的默认插件。虽然我们一般不需要来自定义插件&#xff0c;但是为了使用的过程中更加的清晰&#xff0c;来尝试自定义插件还是很有必要的&#xff0c;所以本文就一起来…

工程实践:如何使用SU17无人机来实现室内巡检任务

阿木实验室最近发布了科研开发者版本的无人机SU17&#xff0c;该无人机上集成了四目视觉&#xff0c;三维激光雷达&#xff0c;云台吊舱&#xff0c;高算力的机载计算机&#xff0c;是一个非常合适的平台用于室内外巡检场景。同时阿木实验室维护了多个和无人机相关的开源项目。…

【瞎折腾/Dify】使用docker离线部署Dify

文章目录 说在前面安装Docker(外网)获取Dify源码(外网)拉取docker镜像(外网)导出镜像(内网)导入镜像(内网)运行问题 说在前面 外网操作系统&#xff1a;windows内网操作系统&#xff1a;ubuntu外网docker desktop版本&#xff1a;4.29.0外网docker版本&#xff1a;version 26.0…

【Git】配置Git

配置Git 忽略特殊文件 在日常开发中&#xff0c;有些文件不想或不应该提交到远端&#xff0c;如保存数据库密码的配置文件。 在Git工作区的根目录下创建一个特殊的.gitignore文件&#xff0c;把要忽略的文件名填进去&#xff0c;Git就会自动忽略这些文件。 不需要从头写.gi…

mysql学习-常用sql语句

1、安装mysql参考网上链接&#xff0c;进入mysql数据库 mysql -u root -p 2、数据库操作 2.1、创建数据库 create database 数据库名 default character set utf8; 2.2、显示所有数据库 show databases; 2.3、选择数据库 use elementInfo; 2.4、删除数据库 drop database…

PostgreSQL16 的双向逻辑复制

一、配置 双向逻辑复制具体步骤 参考:PostgreSQL 16 双向逻辑复制与事务回环控制 - 墨天轮 1. 安装和准备环境 确保在所有参与复制的服务器上都安装了 PostgreSQL 16。主服务器&#xff1a;192.168.0.100从服务器&#xff1a;192.168.0.102 2. 配置 PostgreSQL 在每个服务…

FastAPI复杂查询终极指南:告别if-else的现代化过滤架构

title: FastAPI复杂查询终极指南:告别if-else的现代化过滤架构 date: 2025/3/14 updated: 2025/3/14 author: cmdragon excerpt: 本文系统讲解FastAPI中复杂查询条件的构建方法,涵盖参数验证、动态过滤、安全防护等18个核心技术点。通过引入策略模式、声明式编程等技术,彻…

C++前缀和

个人主页&#xff1a;[PingdiGuo_guo] 收录专栏&#xff1a;[C干货专栏] 大家好&#xff0c;今天我们来了解一下C的一个重要概念&#xff1a;前缀和 目录 1.什么是前缀和 2.前缀和的用法 1.前缀和的定义 2.预处理前缀和数组 3.查询区间和 4.数组中某个区间的和是否为特定…

机器学习基础

目录 泛化误差 偏差和方差 噪声 生成模型和判别模型 正态分布&#xff08;Normal Distribution&#xff09; 超参数选择 Grid Search 网格搜索 Random Search 随机搜索 Hyperopt Hyperas 参数估计方法对比 MLE 最大似然估计 MAP最大后验估计 贝叶斯估计 距…