~~斜率DP初探~~[LOJ10190][APIO2010][Bzoj1911]特别行动队

2 篇文章 0 订阅
1 篇文章 0 订阅

写在前面

斜率Dp貌似算是Dp优化中最难之一了吧~~(要不然LOJ干嘛把他放最后)~~
我也是一直处于深沉的懵逼之中,不敢去动它
今天问了一下同寝的Dalao CLY,终于对最简单的斜率Dp有了一丢丢的了解&理解吧


直接到题目里来看吧:

Problem:

给出N个数,分成任意个连续段,每段的价值为 a ∗ S 2 + b ∗ S + c , 其 中 S = ∑ X i a*S^2+b*S+c,其中S=\sum X_i aS2+bS+cS=Xi
求最大价值和
N<= 1 0 6 10^6 106 X i X_i Xi>=0

Solution

考虑原始Dp
F[i]表示前i个的最大价值和
则易得
F [ i ] = m a x ( F [ j ] + v a l ( j , i ) ) F[i]=max(F[j]+val(j,i)) F[i]=max(F[j]+val(j,i))
O ( N 2 ) O(N^2) O(N2) 、、、
然后好像毫无办法


重头戏来了!

(貌似也是斜率Dp基本步骤)
我们任取i的前继状态j,k,不妨令j>k
那么j比k优的条件是什么?

F [ j ] + a ∗ ( S [ i ] − S [ j ] ) 2 + b ∗ ( S [ i ] − S [ j ] ) + c &gt; F [ j ] + a ∗ ( S [ i ] − S [ k ] ) 2 + b ∗ ( S [ i ] − S [ k ] ) + c F[j]+a*(S[i]-S[j])^2+b*(S[i]-S[j])+c&gt;F[j]+a*(S[i]-S[k])^2+b*(S[i]-S[k])+c F[j]+a(S[i]S[j])2+b(S[i]S[j])+c>F[j]+a(S[i]S[k])2+b(S[i]S[k])+c

看不出什么?继续!

F [ j ] + a ∗ ( S [ j ] 2 − 2 ∗ S [ i ] ∗ S [ j ] ) − b ∗ S [ j ] &gt; F [ k ] + a ∗ ( S [ k ] 2 − 2 ∗ S [ i ] ∗ S [ k ] ) − b ∗ S [ k ] F[j]+a*(S[j]^2-2*S[i]*S[j])-b*S[j]&gt;F[k]+a*(S[k]^2-2*S[i]*S[k])-b*S[k] F[j]+a(S[j]22S[i]S[j])bS[j]>F[k]+a(S[k]22S[i]S[k])bS[k]

由于和i有关的量都可以看成是常量,我们把有i的都移到一边

F [ j ] − F [ k ] + a ∗ S [ j ] 2 − a ∗ S [ k ] 2 − b ∗ S [ j ] − b ∗ S [ k ] &gt; 2 ∗ a ∗ S [ i ] ∗ ( S [ j ] − S [ k ] ) F[j]-F[k]+a*S[j]^2-a*S[k]^2-b*S[j]-b*S[k]&gt;2*a*S[i]*(S[j]-S[k]) F[j]F[k]+aS[j]2aS[k]2bS[j]bS[k]>2aS[i](S[j]S[k])

有没有发现左边有点东西,我们把j,k分别整齐排列

( F [ j ] + a ∗ S [ j ] 2 − b ∗ S [ j ] ) − ( F [ k ] + a ∗ S [ k ] 2 − b ∗ S [ k ] ) &gt; = 2 ∗ a ∗ S [ i ] ∗ ( S [ j ] − S [ k ] ) (F[j]+a*S[j]^2-b*S[j])-(F[k]+a*S[k]^2-b*S[k])&gt;=2*a*S[i]*(S[j]-S[k]) (F[j]+aS[j]2bS[j])(F[k]+aS[k]2bS[k])>=2aS[i](S[j]S[k])

设 Y [ x ] = F [ x ] + a ∗ S [ x ] 2 − b ∗ S [ x ] 设Y[x]=F[x]+a*S[x]^2-b*S[x] Y[x]=F[x]+aS[x]2bS[x],再把S[j]-S[k]除过去

Y [ j ] − Y [ k ] S [ j ] − S [ k ] &gt; = 2 ∗ a ∗ S [ i ] \frac{Y[j]-Y[k]}{S[j]-S[k]}&gt;=2*a*S[i] S[j]S[k]Y[j]Y[k]>=2aS[i]

或者再明显一点~~

Y [ j ] − Y [ k ] X [ j ] − X [ k ] &gt; = 2 ∗ a ∗ S [ i ] \frac{Y[j]-Y[k]}{X[j]-X[k]}&gt;=2*a*S[i] X[j]X[k]Y[j]Y[k]>=2aS[i]

再懂得斜率Dp的意思了吗?左边不就是个斜率吗!!!

因为Xi>=0,所以Si是递增的,即斜率是递增的,那么用一个单调队列维护斜率不就好了吗QWQ

Easy Code

#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define pt(ch) (Top<1000000?St[Top++]=ch:(Out(),St[(Top=0)++]=ch))
#define Out() (fwrite(St,1,Top,stdout))
#define LL long long
using namespace std;
int Top;static char St[1000000],buf[1000000],*p1=buf,*p2=buf;
const int maxn=(1e6)+5;
int N,hd,tl,Q[maxn];LL X[maxn],Y[maxn],F[maxn];int a,b,c;
int Re(){
	int ret=0;bool f=0;char ch=gt();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
	while(ch>='0'&&ch<='9') ret=ret*10+(ch^'0'),ch=gt();
	return f?-ret:ret;
}
void Wri(int x){if(x<0) x=-x,pt('-');if(x>9) Wri(x/10);pt(x%10+'0');}
#define sqr(x) ((x)*(x))
int main(){
	#ifdef hhh
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	#endif
	N=Re(),a=Re(),b=Re(),c=Re();
	for(int i=1,D;i<=N;i++){
		X[i]=X[i-1]+Re();
		while(hd<tl&&Y[Q[hd+1]]-Y[Q[hd]]>=a*X[i]*(X[Q[hd+1]]-X[Q[hd]])<<1) hd++;
		F[i]=F[Q[hd]]+a*sqr(D=X[i]-X[Q[hd]])+b*D+c,Y[i]=F[i]+a*sqr(X[i])-b*X[i];
		while(hd<tl&&(Y[i]-Y[Q[tl]])*(X[Q[tl]]-X[Q[tl-1]])>=(Y[Q[tl]]-Y[Q[tl-1]])*(X[i]-X[Q[tl]])) tl--;
		//即(Y[i]-Y[Q[tl]])/(X[i]-X[Q[tl]])>=(Y[Q[tl]]-Y[Q[tl-1]])/(X[Q[tl]]-X[Q[tl-1]])--->ki>kt
		Q[++tl]=i;
	}
	printf("%lld\n",F[N]);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值