P3195 [HNOI2008]玩具装箱 题解

我数学好弱啊,这种题都能卡
f i f_i fi为压缩完1~i的玩具的最优解,不难列出状态转移方程:
f i = min ⁡ { f j + [ q i − q j + i − ( j + 1 ) − L ] 2 } ( j < i ) f_i=\min\{f_j+[q_i-q_j+i-(j+1)-L]^2\}(jfi=min{fj+[qiqj+i(j+1)L]2}(j<i),其中 q i = ∑ k = 1 i C k q_i=\sum_{k=1}^iC_k qi=k=1iCk
明显是 O ( n 2 ) O(n^2) O(n2)的式子, n ≤ 5 e 4 n \le 5e4 n5e4这种数据肯定过不去。
就要用到一些奇怪的优化了,比如斜率优化。
s i = q i + i s_i=q_i+i si=qi+i L ′ = L + 1 L'=L+1 L=L+1
f i = min ⁡ { f j + [ ( s i − s j ) − L ′ ] 2 } ( j < i ) f_i=\min\{f_j+[(s_i-s_j)-L']^2\}(jfi=min{fj+[(sisj)L]2}(j<i)
现在有两个数 j , k j,k j,k,满足 i > j > k i>j>k i>j>k,令状态 k k k优于状态 j j j,得
f k + ( s i − s k − L ′ ) 2 ≤ f j + ( s i − s j − L ′ ) 2 遇 见 式 子 直 接 拆 , 得 f k + [ s i − ( s k + L ′ ) ] 2 ≤ f j + [ s i − ( s j + L ′ ) ] 2 f k + s i 2 − 2 s i ( s k + L ′ ) + ( s k + L ′ ) 2 ≤ f j + s i 2 − 2 s i ( s j + L ′ ) + ( s j + L ′ ) 2 化 简 , 得 f k − 2 s i ( s k + L ′ ) + ( s k + L ′ ) 2 ≤ f j − 2 s i ( s j + L ′ ) + ( s j + L ′ ) 2 把 有 s i 项 的 移 到 一 起 , 得 − 2 s i ( s k + L ′ ) + 2 s i ( s j + L ′ ) ≤ − f k + f j − 2 s i ( s j + L ′ ) + 2 s i ( s k + L ′ ) − ( s k + L ′ ) 2 + ( s j + L ′ ) 2 两 边 都 乘 − 1 , 得 2 s i ( s k + L ′ ) − 2 s i ( s j + L ′ ) ≤ f k − f j + 2 s i ( s k + L ′ ) − 2 s i ( s k + L ′ ) + ( s k + L ′ ) 2 − ( s j + L ′ ) 2 s i [ 2 ( s k + L ′ ) − 2 ( s j + L ′ ) ] ≤ f k − f j + 2 s i ( s k + L ′ ) − 2 s i ( s k + L ′ ) + ( s k + L ′ ) 2 − ( s j + L ′ ) 2 s i ≤ f k − f j + 2 s i ( s k + L ′ ) − 2 s i ( s k + L ′ ) + ( s k + L ′ ) 2 − ( s j + L ′ ) 2 2 ( s k + L ′ ) − 2 ( s j + L ′ ) 设 X i = 2 s i , Y i = f i + ( s i + L ′ ) 2 得 s i ≤ Y k − Y j X k − X j 嗯 , 这 么 眼 熟 , 高 中 书 上 的 斜 率 ? f_k+(s_i-s_k-L')^2 \le f_j+(s_i-s_j-L')^2\\ 遇见式子直接拆,得f_k+[s_i-(s_k+L')]^2 \le f_j+[s_i-(s_j+L')]^2\\ f_k+s_i^2-2s_i(s_k+L')+(s_k+L')^2 \le f_j+s_i^2-2s_i(s_j+L')+(s_j+L')^2\\ 化简,得f_k-2s_i(s_k+L')+(s_k+L')^2 \le f_j-2s_i(s_j+L')+(s_j+L')^2\\ 把有s_i项的移到一起,得-2s_i(s_k+L')+2s_i(s_j+L') \le -f_k+f_j-2s_i(s_j+L')+2s_i(s_k+L')-(s_k+L')^2+(s_j+L')^2\\ 两边都乘-1,得2s_i(s_k+L')-2s_i(s_j+L') \le f_k-f_j+2s_i(s_k+L')-2s_i(s_k+L')+(s_k+L')^2-(s_j+L')^2\\ s_i[2(s_k+L')-2(s_j+L')] \le f_k-f_j+2s_i(s_k+L')-2s_i(s_k+L')+(s_k+L')^2-(s_j+L')^2\\ s_i \le \frac{ f_k-f_j+2s_i(s_k+L')-2s_i(s_k+L')+(s_k+L')^2-(s_j+L')^2}{2(s_k+L')-2(s_j+L')}\\ 设X_i=2s_i,Y_i=f_i+(s_i+L')^2\\ 得 s_i \le \frac{Y_k-Y_j}{X_k-X_j}\\ 嗯,这么眼熟,高中书上的斜率?\\ fk+(siskL)2fj+(sisjL)2fk+[si(sk+L)]2fj+[si(sj+L)]2fk+si22si(sk+L)+(sk+L)2fj+si22si(sj+L)+(sj+L)2fk2si(sk+L)+(sk+L)2fj2si(sj+L)+(sj+L)2si2si(sk+L)+2si(sj+L)fk+fj2si(sj+L)+2si(sk+L)(sk+L)2+(sj+L)212si(sk+L)2si(sj+L)fkfj+2si(sk+L)2si(sk+L)+(sk+L)2(sj+L)2si[2(sk+L)2(sj+L)]fkfj+2si(sk+L)2si(sk+L)+(sk+L)2(sj+L)2si2(sk+L)2(sj+L)fkfj+2si(sk+L)2si(sk+L)+(sk+L)2(sj+L)2Xi=2si,Yi=fi+(si+L)2siXkXjYkYj
P3195 [HNOI2008]玩具装箱 题解_第1张图片图片来源:原题luogu题解

可以发现 s i s_i si是单调上升的,然后非常simple画个图像(直接到洛谷上去找吧),发现是下凸包,我们只要找第一个 s l o p e ( P j , P j + 1 ) > s i slope(P_j,P_{j+1})>s_i slope(Pj,Pj+1)>si的点,那么既可以用二分 O ( n l o g n ) O(nlogn) O(nlogn),也可以用单调队列 O ( n ) O(n) O(n),不过需要四边形不等式证明一下(口胡?不会),GG。
好像就结束了啊,放个代码:

# include 
using namespace std;
const int N=5e4+5;
int n,L;
long long q[N];
long long dp[N];
int Q[N<<2];
int front,rear;
long long sq(long long x) {return x*x;}
long long X(int i) 
{
	return 2.0*q[i];
}
long long Y(int i) 
{
	return (dp[i])+sq((q[i])+(L+1));
}
long double slope(int i,int j) 
{
	return (long double)(Y(j)-Y(i))/(X(j)-X(i));
}
int main(void) 
{
	scanf("%d%d",&n,&L);
	long long x;
	for(int i=1;i<=n;i++) 
	{
		scanf("%lld",&x);
		q[i]=q[i-1]+x+1;
	}
	front=rear=0;
	Q[++rear]=0;
	for(int i=1;i<=n;i++) 
	{
		while(front+1<rear&&slope(Q[front+1],Q[front+2])<=q[i]) front++;
		int head=Q[front+1];
		dp[i]=dp[head]+sq(q[i]-q[head]-L-1);
		while(front+1<rear&&slope(Q[rear-1],i)<slope(Q[rear],Q[rear-1])) rear--;
		Q[++rear]=i;
	}
	cout<<dp[n]<<endl;
	return 0;
}

你可能感兴趣的:(斜率dp,dp)