bzoj3437 小P的牧场(斜率优化dp)

3437: 小P的牧场

每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场

这时候逆推显然比正推好用

于是我们设$s[i]$为$b[i]$的前缀和,$f[i]$为只在第$i$~$n$个牧场中设置控制站,且在牧场$i$设置控制站的最小代价

$f[i]=f[j]-(j-i)*s[i]+a[i]$

$f[j]=s[i]*j+f[i]+i*s[i]+a[i]$

又化成了喜闻乐见的$y=k*x+b$

$y=f[j]$

$k=s[i]$

$x=j$

$b=f[i]+i*s[i]+a[i]$

$k,x$均单调

于是我们就可以快乐地单调队列维护凸包解决辣·

#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
using namespace std;
typedef long long ll;
#define N 1000005
ll a[N],b[N],s[N],f[N],ans;
int n,L,R,h[N];
inline ll X(int i){return i;}
inline ll Y(int i){return f[i];}
inline ll KK(ll xa,ll ya,ll xb,ll yb){return ya*xb-yb*xa;}
int main(){
    //freopen("bzoj3437.in","r",stdin);
    scanf("%d",&n);
    for(rint i=1;i<=n;++i) scanf("%lld",&a[i]);
    for(rint i=1;i<=n;++i) scanf("%lld",&b[i]),s[i]=s[i-1]+b[i];
    for(rint i=n-1;i;--i) f[n]+=1ll*(n-i)*b[i];
    f[n]+=a[n]; ans=f[n]; h[L=R=1]=n;//先把f[n]算出来
    for(rint i=n-1;i;--i){
        while(L<R&&KK(X(h[L+1])-X(h[L]),Y(h[L+1])-Y(h[L]),
        1,s[i])<=0) ++L;
         
        f[i]=f[h[L]]-1ll*(h[L]-i)*s[i]+a[i];
        ans=min(ans,f[i]);
        
        while(L<R&&KK(X(h[R])-X(h[R-1]),Y(h[R])-Y(h[R-1]),
        X(h[R])-X(i),Y(h[R])-Y(i))>=0) --R;
        
        h[++R]=i;
    }printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10758986.html