【题目链接】

ybt 1612:特别行动队
洛谷 P3628 [APIO2010] 特别行动队

【题目考点】

1. 动态规划:斜率优化动规

斜率优化的具体原理、和代码细节参考模板题:
信息学奥赛一本通 1607:【 例 2】任务安排 2 | 洛谷 P10979 任务安排 2

【解题思路】

给定整数序列 x x x,每个整数是一个元素,每个行动队是该序列的一个子段。根据计算可以得到该行动队的战斗力,将战斗力叫做费用

状态定义

  • 阶段:前i个元素
  • 决策:是否将第i加入子段
  • 策略:子段划分的方案
  • 策略集合:前i个元素的所有子段划分方案。
  • 条件:费用最大
  • 统计量:费用

状态定义 d p i dp_i dpi:前i个元素的所有子段划分方案中,费用最大的方案的费用。
初始状态 d p 0 = 0 dp_0=0 dp0=0

状态转移方程

  • 策略集合:前 i i i个元素的所有子段划分方案。
  • 分割策略集合:根据最后一个子段的起始位置分割策略集合。
    记最后一个子段的起始位置为 j + 1 j+1 j+1 j j j最小为 0 0 0,最大为 i − 1 i-1 i1,因此 0 ≤ j ≤ i − 1 0\le j \le i-1 0ji1
    j j j个元素进制子段划分得到的最大费用为 d p j dp_{j} dpj
    j + 1 j+1 j+1到第 i i i元素贡献的费用为: x = ∑ k = j + 1 i x k x=\sum_{k=j+1}^ix_k x=k=j+1ixk,而后费用为 a x 2 + b x + c ax^2+bx+c ax2+bx+c
    x x x序列的前缀和为 s x sx sx,则 x = s x i − s x j x=sx_i-sx_{j} x=sxisxj,所需费用为 a ( s x i − s x j ) 2 + b ( s x i − s x j ) + c a(sx_i-sx_j)^2+b(sx_i-sx_j)+c a(sxisxj)2+b(sxisxj)+c
    对于 j j j的所有可能取值,取费用的最小值。
    状态转移方程为:
    d p i = m i n { d p j + a ( s x i − s x j ) 2 + b ( s x i − s x j ) + c } , 0 ≤ j ≤ i − 1 dp_i=min\{dp_j+a(sx_i-sx_j)^2+b(sx_i-sx_j)+c\},0\le j \le i-1 dpi=min{dpj+a(sxisxj)2+b(sxisxj)+c}0ji1

进行斜率优化动规,去掉min,将与 j j j相关的表达式视为变量
− d p j = − d p i + a ( s x i 2 − 2 s x i ⋅ s x j + s x j 2 ) + b ⋅ s x i − b ⋅ s x j + c -dp_j=-dp_i+a(sx_i^2-2sx_i\cdot sx_j+sx_j^2)+b\cdot sx_i-b\cdot sx_j+c dpj=dpi+a(sxi22sxisxj+sxj2)+bsxibsxj+c
− d p j − a ⋅ s x j 2 + b ⋅ s x j = − 2 a ⋅ s x i ⋅ s x j − d p i + a ⋅ s x i 2 + b ⋅ s x i + c -dp_j-a\cdot sx_j^2+b\cdot sx_j = -2a\cdot sx_i\cdot sx_j-dp_i+a\cdot sx_i^2+b\cdot sx_i+c dpjasxj2+bsxj=2asxisxjdpi+asxi2+bsxi+c

解法1: 斜率 k k k随着 i i i的增大单调递增

(建议将斜率 k k k设计为随着 i i i的增大单调递增,这样方便写固定的模板代码,减少出错。)
设:
y = − d p j − a ⋅ s x j 2 + b ⋅ s x j y=-dp_j-a\cdot sx_j^2+b\cdot sx_j y=dpjasxj2+bsxj
x = s x j x=sx_j x=sxj
k = − 2 a ⋅ s x i k=-2a\cdot sx_i k=2asxi
b = − d p i + a ⋅ s x i 2 + b ⋅ s x i + c b=-dp_i+a\cdot sx_i^2+b\cdot sx_i+c b=dpi+asxi2+bsxi+c
则该方程为 y = k x + b y=kx+b y=kx+b,直线斜率固定,看过哪个决策点 ( s x j , − d p j − a ⋅ s x j 2 + b ⋅ s x j ) (sx_j,-dp_j-a\cdot sx_j^2+b\cdot sx_j) (sxj,dpjasxj2+bsxj)时直线截距最小,此时 d p i dp_i dpi最大。
由于已知 a < 0 a<0 a<0,直线斜率 k = − 2 a ⋅ s x i k=-2a\cdot sx_i k=2asxi随着 i i i的增大而增大。
使用单调队列 q q q维护决策点集的下凸壳, q l q_l ql是队头, q r q_r qr是队尾。单调队列中相邻两决策点连线的斜率是单调递增的。
K ( a , b ) K(a,b) K(a,b) a a a b b b两个决策点连线的斜率。
每次循环新加入决策点为 j = i − 1 j=i-1 j=i1,只要 K ( q r , i − 1 ) ≤ K ( q r − 1 , q r ) K(q_r,i-1)\le K(q_{r-1}, q_r) K(qr,i1)K(qr1,qr),则队尾出队,当 K ( q r , i − 1 ) > K ( q r − 1 , q r ) K(q_r,i-1)> K(q_{r-1}, q_r) K(qr,i1)>K(qr1,qr)时将 i − 1 i-1 i1队尾入队。
只要 K ( q l , q l + 1 ) ≤ − 2 a ⋅ s x i K(q_l,q_{l+1})\le -2a\cdot sx_i K(ql,ql+1)2asxi,则队头出队。
队头 q l q_l ql就是最优决策点,令 j = q l j=q_l j=ql,代入状态转移方程,求出 d p i dp_i dpi
最终结果为 d p n dp_n dpn

解法2: 斜率 k k k随着 i i i的增大单调递减

− d p j − a ⋅ s x j 2 + b ⋅ s x j = − 2 a ⋅ s x i ⋅ s x j − d p i + a ⋅ s x i 2 + b ⋅ s x i + c -dp_j-a\cdot sx_j^2+b\cdot sx_j = -2a\cdot sx_i\cdot sx_j-dp_i+a\cdot sx_i^2+b\cdot sx_i+c dpjasxj2+bsxj=2asxisxjdpi+asxi2+bsxi+c
等号两侧乘以 − 1 -1 1得:
d p j + a ⋅ s x j 2 − b ⋅ s x j = 2 a ⋅ s x i ⋅ s x j + d p i − a ⋅ s x i 2 − b ⋅ s x i − c dp_j+a\cdot sx_j^2-b\cdot sx_j = 2a\cdot sx_i\cdot sx_j+dp_i-a\cdot sx_i^2-b\cdot sx_i-c dpj+asxj2bsxj=2asxisxj+dpiasxi2bsxic

设:
y = d p j + a ⋅ s x j 2 − b ⋅ s x j y=dp_j+a\cdot sx_j^2-b\cdot sx_j y=dpj+asxj2bsxj
x = s x j x=sx_j x=sxj
k = 2 a ⋅ s x i k=2a\cdot sx_i k=2asxi
b = d p i − a ⋅ s x i 2 − b ⋅ s x i − c b=dp_i-a\cdot sx_i^2-b\cdot sx_i-c b=dpiasxi2bsxic
则该方程为 y = k x + b y=kx+b y=kx+b,直线斜率固定,看过哪个决策点 ( s x j , d p j + a ⋅ s x j 2 − b ⋅ s x j ) (sx_j,dp_j+a\cdot sx_j^2-b\cdot sx_j) (sxj,dpj+asxj2bsxj)时直线截距最大,此时 d p i dp_i dpi最大。
由于已知 a < 0 a<0 a<0,直线斜率 k = 2 a ⋅ s x i k=2a\cdot sx_i k=2asxi随着 i i i的增大而减小。
使用单调队列 q q q维护决策点集的上凸壳, q l q_l ql是队头, q r q_r qr是队尾。单调队列中相邻两决策点连线的斜率是单调递减的。
K ( a , b ) K(a,b) K(a,b) a a a b b b两个决策点连线的斜率。
每次循环新加入决策点为 j = i − 1 j=i-1 j=i1,只要 K ( q r , i − 1 ) ≥ K ( q r − 1 , q r ) K(q_r,i-1)\ge K(q_{r-1}, q_r) K(qr,i1)K(qr1,qr),则队尾出队。当 K ( q r , i − 1 ) < K ( q r − 1 , q r ) K(q_r,i-1)< K(q_{r-1}, q_r) K(qr,i1)<K(qr1,qr)时将 i − 1 i-1 i1队尾入队。
只要 K ( q l , q l + 1 ) ≥ 2 a ⋅ s x i K(q_l,q_{l+1})\ge 2a\cdot sx_i K(ql,ql+1)2asxi,则队头出队。
队头 q l q_l ql就是最优决策点,令 j = q l j=q_l j=ql,代入状态转移方程,求出 d p i dp_i dpi
最终结果为 d p n dp_n dpn

【题解代码】

解法1:斜率 k k k随着 i i i的增大单调递增

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
typedef long long LL;
LL n, a, b, c, x[N], sx[N], dp[N];
int q[N], l = 1, r = 0;
LL X(int j)
{
	return sx[j];
}
LL Y(int j)
{
	return -dp[j]-a*sx[j]*sx[j]+b*sx[j];
}
LL K(int i)
{
	return -2*a*sx[i];
}
bool cmp(LL y1, LL x1, LL y2, LL x2)//y1/x1 <= y2/x2
{
	return y1*x2 <= y2*x1;
}
int main()
{
	cin >> n >> a >> b >> c;
	for(int i = 1; i <= n; ++i)
	{
		cin >> x[i];
		sx[i] = sx[i-1]+x[i];
	}
	for(int i = 1; i <= n; ++i)
	{
		while(l < r && cmp(Y(i-1)-Y(q[r]), X(i-1)-X(q[r]), Y(q[r])-Y(q[r-1]), X(q[r])-X(q[r-1])))
			r--;
		q[++r] = i-1;
		while(l < r && cmp(Y(q[l+1])-Y(q[l]), X(q[l+1])-X(q[l]), K(i), 1))
			l++;
		dp[i] = dp[q[l]]+a*(sx[i]-sx[q[l]])*(sx[i]-sx[q[l]])+b*(sx[i]-sx[q[l]])+c;
	}
	cout << dp[n];
	return 0;
}

解法2:斜率 k k k随着 i i i的增大单调递减

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
typedef long long LL;
LL n, a, b, c, x[N], sx[N], dp[N];
int q[N], l = 1, r = 0;
LL X(int j)
{
	return sx[j];
}
LL Y(int j)
{
	return dp[j]+a*sx[j]*sx[j]-b*sx[j];
}
LL K(int i)
{
	return 2*a*sx[i];
}
bool cmp(LL y1, LL x1, LL y2, LL x2)//y1/x1 >= y2/x2
{
	return y1*x2 >= y2*x1;
}
int main()
{
	cin >> n >> a >> b >> c;
	for(int i = 1; i <= n; ++i)
	{
		cin >> x[i];
		sx[i] = sx[i-1]+x[i];
	}
	for(int i = 1; i <= n; ++i)
	{
		while(l < r && cmp(Y(i-1)-Y(q[r]), X(i-1)-X(q[r]), Y(q[r])-Y(q[r-1]), X(q[r])-X(q[r-1])))
			r--;
		q[++r] = i-1;
		while(l < r && cmp(Y(q[l+1])-Y(q[l]), X(q[l+1])-X(q[l]), K(i), 1))
			l++;
		dp[i] = dp[q[l]]+a*(sx[i]-sx[q[l]])*(sx[i]-sx[q[l]])+b*(sx[i]-sx[q[l]])+c;
	}
	cout << dp[n];
	return 0;
}

Logo

集算法之大成!助力oier实现梦想!

更多推荐