bzoj2726 [SDOI2012]任务安排(cdq分治+斜率优化)

我们显然有n^2 dp
f [ i ] = m i n { f [ j ] + ( S + t [ i ] t [ j ] ) w [ j ] }
其中 t [ i ] = j = 1 i T [ i ] , w [ i ] = j = i + 1 n F [ j ]
然后我们斜率优化一波,设k1< k2,且k2优于k1
f [ k 1 ] f [ k 2 ] t [ k 1 ] w [ k 1 ] + t [ k 2 ] w [ k 2 ] S w [ k 2 ] + S w [ k 1 ] w [ k 2 ] w [ k 1 ] > t [ i ]

但是因为t可以为负数,不单调,于是我们只能cdq分治+斜率优化搞了。
维护上凸壳,提前把询问按斜率排序,直接拿指针扫一遍凸壳即可。两个凸壳合并起来也可以归并做到 O ( n )

复杂度 O ( n l o g n )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double 
#define inf 1e20
#define N 300010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,S,t[N],w[N],q[N];
struct Icefox{
    int x,k,id;
    ll y,f;
    inline bool friend operator<(Icefox a,Icefox b){return a.id<b.id;}
}a[N],b[N];
inline bool cmpk(Icefox a,Icefox b){return a.k>b.k;}
inline ld slope(int k1,int k2){
    if(a[k1].x==a[k2].x) return a[k2].y>=a[k1].y?inf:-inf;
    return ((ld)a[k2].y-a[k1].y)/(a[k2].x-a[k1].x);
}
inline void solve(int l,int r){
    if(l==r){a[l].y=(ll)(a[l].k-S)*a[l].x-a[l].f;return;}
    int mid=l+r>>1,p1=l,p2=mid+1;
    for(int i=l;i<=r;++i){
        if(a[i].id<=mid) b[p1++]=a[i];
        else b[p2++]=a[i];
    }memcpy(a+l,b+l,sizeof(a[0])*(r-l+1));
    solve(l,mid);int qh=1,qt=0;
    for(int i=l;i<=mid;++i){
        while(qh<qt&&slope(q[qt],i)>=slope(q[qt-1],q[qt])) --qt;
        q[++qt]=i;
    }for(int i=mid+1;i<=r;++i){
        while(qh<qt&&slope(q[qh],q[qh+1])>=a[i].k) ++qh;
        a[i].f=min(a[i].f,a[q[qh]].f+(ll)(S+a[i].k-a[q[qh]].k)*a[q[qh]].x);
    }solve(mid+1,r);p1=l,p2=mid+1;
    for(int i=l;i<=r;++i){
        if(p2>r||a[p1].x<=a[p2].x) b[i]=a[p1++];
        else b[i]=a[p2++];
    }memcpy(a+l,b+l,sizeof(a[0])*(r-l+1));
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();S=read();
    for(int i=1;i<=n;++i) t[i]=read(),w[i]=read();
    for(int i=1;i<=n;++i) t[i]+=t[i-1],a[i].k=t[i];
    for(int i=n;i>=1;--i) w[i]+=w[i+1],a[i].x=w[i+1];
    for(int i=1;i<=n;++i) a[i].f=(ll)(S+t[i])*w[1],a[i].id=i;
    sort(a+1,a+n+1,cmpk);
    solve(1,n);sort(a+1,a+n+1);
    printf("%lld\n",a[n].f);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Icefox_zhx/article/details/80896683
今日推荐