斜率优化——libreOj10192

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define N 500005
struct point{
    ll x,y;
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
};
ll cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
point q[N]; 
int head,tail;
void pop(ll k){
    while(tail>head && q[head+1].y-q[head].y<=k*(q[head+1].x-q[head].x))
        head++;
}
void push(point k1){
    while(tail>head && cross(q[tail]-k1,q[tail-1]-k1)>=0)tail--;
    q[++tail]=k1;
}

ll n,dp[N],d[N],w[N],sumd[N],sumw[N],c[N];

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%lld%lld",&w[i],&d[i]);
    for(int i=1;i<=n+1;i++)sumw[i]=sumw[i-1]+w[i];
    for(int i=1;i<=n+1;i++)sumd[i]=sumd[i-1]+d[i-1];
    for(int i=1;i<=n+1;i++)c[i]=c[i-1]+d[i-1]*sumw[i-1];//把所有树移到位置i的代价 
    
    ll ans=0x3f3f3f3f3f3f3f3f;
    head=tail=1;
    q[1]=(point){sumw[1],sumw[1]*sumd[1]};//第一个点已经在图上了 
    for(int i=2;i<=n;i++){
        pop(sumd[i]);
        dp[i]=q[head].y-q[head].x*sumd[i];
        dp[i]+=c[n+1]-sumw[i]*sumd[n+1]+sumw[i]*sumd[i]; 
        push((point){sumw[i],sumw[i]*sumd[i]});
        ans=min(ans,dp[i]);
        //cout<<dp[i]<<" "<<head<<" "<<tail<<"
";
    }
    
    cout<<ans<<'
';
} 
原文地址:https://www.cnblogs.com/zsben991126/p/12520423.html