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

题目传送门
这题和bzoj1492Cash几乎一样,所以这里只贴公式。
f[i]=min(f[j]+c[j](t[i]t[j]+s))
=>f[k]+c[k]t[i]c[k](t[k]s)<=f[j]+c[j]t[i]c[j](t[j]s)
=>f[k]+c[k]t[i]c[k]t[k]+c[k]s<=f[j]+c[j]t[i]c[j]t[j]+c[j]s
=>(f[k]c[k]t[k]+c[k]s)(f[j]c[j]t[j]+c[j]s)<=(c[j]c[k])t[i]
=>((f[k]c[k]t[k]+c[k]s)(f[j]c[j]t[j]+c[j]s))/(c[j]c[k])<=t[i]
然后用cdq分治优化即可。
细节详见代码。

#include<cstdio>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;
const int N=300005;
int n,q[N];
ll s,f[N];
struct data{
    ll t,c;
    int id;
    friend bool operator < (const data &a,const data &b){
        return a.t<b.t;
    }
}a[N],b[N];
inline int rd(){
    register int res=0,f=1;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        res=res*10+ch-'0';
        ch=getchar();
    }
    return res*f;
}
ll get(int i){
    return f[a[i].id]-a[i].c*a[i].t+a[i].c*s;
}
ll getx(int j,int k){
    return get(k)-get(j);
}
ll gety(int j,int k){
    return a[j].c-a[k].c;
}
void solve(int l,int r){
    if(l==r){
        return;
    }
    register int mid=(l+r)/2,j=l,k=mid+1;
    for(register int i=l;i<=r;i++){
        if(a[i].id<=mid){
            b[j++]=a[i];
        }else{
            b[k++]=a[i];
        }
    }
    for(register int i=l;i<=r;i++){
        a[i]=b[i];
    }
    solve(l,mid);
    j=1,k=0;
    for(register int i=l;i<=mid;i++){
        while(j<k&&getx(q[k],i)*gety(q[k-1],q[k])<getx(q[k-1],q[k])*gety(q[k],i)){
            k--;
        }
        q[++k]=i;
    }
    for(register int i=mid+1;i<=r;i++){
        while(j<k&&getx(q[j],q[j+1])<=a[i].t*gety(q[j],q[j+1])){
            j++;
        }
        if(j<=k){
            f[a[i].id]=min(f[a[i].id],f[a[q[j]].id]+a[q[j]].c*(a[i].t-a[q[j]].t+s));
        }
    }
    solve(mid+1,r);
    j=l,k=mid+1;
    for(register int i=l;i<=r;i++){
        if(j<=mid&&(k>r||a[j].c>=a[k].c)){
            b[i]=a[j++];
        }else{
            b[i]=a[k++];
        }
    }
    for(register int i=l;i<=r;i++){
        a[i]=b[i];
    }
}
signed main(){
    scanf("%d%lld",&n,&s);
    for(register int i=1;i<=n;i++){
        scanf("%lld%lld",&a[i].t,&a[i].c);
        a[i].t+=a[i-1].t;
        a[i].c+=a[i-1].c;
        a[i].id=i;
    }
    ll tmp=a[n].c;
    for(register int i=n;i>=0;i--){
        a[i].c=tmp-a[i].c;
    }
    for(register int i=1;i<=n;i++){
        f[i]=a[0].c*(a[i].t+s);
    }
    sort(a+1,a+n+1);
    solve(1,n);
    printf("%lld",f[n]);
    return 0;
}
posted @ 2018-04-05 21:03  ez_2016gdgzoi471  阅读(97)  评论(0编辑  收藏  举报