1 window.cnblogsConfig = { 2 homeBannerTextType: "one", //one为每日一句话,若采用homBannerText自己设置,则显示自己设置标语优先显示 3 } 4 5 /** 所有可配置项 6 jinrishici:每次刷新随机获取一句古诗词。 7 one:每日获取一句话 8 */

斜率优化再整理

我是sb,这东西学了多久还不熟,故整理此文

P3195 [HNOI2008]玩具装箱

当$dp$方程为$dp[i]=a[i]+b[j]$时,这个方程可以用单调队列从$O(n^2)$优化到$O(n)$

而当$dp$方程为$dp[i]=a[i]*b[j]+c[i]+d[j]$时,由于存在$a[i]*b[j]$这种既有$i$又有$j$的项,以上方法就不能用了,这就引入了斜率优化

对于本题,有$dp$方程:

$dp[i]=\min(dp[j]+(sum[i]+i-sum[j]-j-L-1)^2)(j<i)$

设$a[i]=sum[i]+i,b[i]=sum[i]+i+L+1$,则:

$dp[i]=dp[j]+(a[i]-b[j])^2=dp[j]+a[i]^2-2*a[i]*b[j]+b[j]^2$

移项得:

$2*a[i]*b[j]+dp[i]-a[i]^2=dp[j]+b[j]^2$

可以看作一条斜率为$2*a[i]$的直线,过点$(b[j],dp[j]+b[j]^2)$($b[j]$单增,$a[i]$单增)

$dp[i]$的含义即为:当直线过点$(b[j],dp[j]+b[j]^2)$时,在$y$轴的截距加上$a[i]^2$

下面就找斜率的最小值,显然当直线从下往上平移,在遇到第一个点时,此时的斜率是最小的

相当于维护一个凸包

P3628 [APIO2010]特别行动队

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<set> 
#include<cstdlib>
#include<ctime>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define lowbit(x) ((x)&(-x))
#define For(x,i,j) for(int x=(i);x<=(j);x++)
#define FOR(x,i,j) for(int x=(i);x>=(j);x--)
#define ls(o) (o<<1)
#define rs(o) (o<<1|1)
#define debug(x) cout<<"debug : "<<x<<endl;
inline int read(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*w;
}
const int N=1000005;
LL n,a,b,c,x[N],s[N];
LL dp[N],q[N];
LL K(int i){
    return 2*a*s[i];
}
LL X(int i){
    return s[i];
}
LL Y(int i){
    return dp[i]+a*s[i]*s[i]-b*s[i];
}
double Slope(int i,int j){
    return 1.0*(Y(j)-Y(i))/(X(j)-X(i));
}
int main(){
    //dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c
    cin>>n>>a>>b>>c;
    for(int i=1;i<=n;i++) cin>>x[i],s[i]=s[i-1]+x[i];
    int head=0,tail=0;
    for(int i=1;i<=n;i++){
        while(head<tail&&Slope(q[head],q[head+1])>K(i)) head++;
        //dp[i]=-K(i)*X(q[head])+Y(q[head])+a*s[i]*s[i]+b*s[i]+c;
        dp[i]=dp[q[head]]+a*(s[i]-s[q[head]])*(s[i]-s[q[head]])+b*(s[i]-s[q[head]])+c;
        while(head<tail&&Slope(q[tail-1],q[tail])<=Slope(q[tail],i)) tail--;
        q[++tail]=i;
    }
    cout<<dp[n];
    return 0;
}

 

posted @ 2021-02-18 10:48  FL4K  阅读(19)  评论(0编辑  收藏  举报
5 6