BZOJ_2726_[SDOI2012]任务安排_斜率优化+二分

BZOJ_2726_[SDOI2012]任务安排_斜率优化+二分

Description

机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。

Input

第一行两个整数,N,S。
接下来N行每行两个整数,Ti,Fi。

Output

一个整数,为所求的答案。

Sample Input

5 1
1 3
3 2
4 3
2 3
1 4

Sample Output

153

设F[i]表示前i个任务完成后最小的代价。
然后把后面的代价提前计算。
设sx[],sy[]分别为x,y的前缀和。
F[i]=F[j]+(m+sx[i]-sx[j])*(sy[n]-sy[j])。设sum=sy[n]。
然后斜率优化:F[i]=-sy[j]*sx[i]  -sx[j]*sum-m*sy[j]+sx[j]*sy[j]  +m*sum+sx[i]*sum
把决策点当成直线,斜率-sy[j]单调减。
于是维护一个上凸壳。
但是每次查询的X(i)=sx[i]不一定单调。
因此不能乱弹队首。每次二分一下当前凸壳上交点离X(i)最近的大于X(i)位置,这个位置最优。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define N 300050
int n,m,xx[N],yy[N],Q[N],l,r;
ll f[N],sx[N],sy[N],sum;
ll K(int j) {
    return -sy[j];
}
ll B(int j) {
    return f[j]-sx[j]*sum-m*sy[j]+sx[j]*sy[j];
}
ll Y(int i,int j) {
    return K(j)*sx[i]+B(j);
}
bool cover(int p1,int p2,int p3) {
    // return (K(p1)-K(p3))*(B(p2)-B(p1))>=(K(p1)-K(p2))*(B(p3)-B(p1));
    return (K(p2)-K(p3))*(B(p1)-B(p3))<=(B(p3)-B(p2))*(K(p3)-K(p1));
}
bool check(int p1,int p2,int i) {
    return B(p1)-B(p2)>=sx[i]*(K(p2)-K(p1));
}
int main() {
    scanf("%d%d",&n,&m);
    int i,j;
    for(i=1;i<=n;i++) {
        scanf("%d%d",&xx[i],&yy[i]);
        sx[i]=sx[i-1]+xx[i];
        sy[i]=sy[i-1]+yy[i];
    }
    sum=sy[n];
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    /*for(i=1;i<=n;i++) {
        for(j=0;j<i;j++) {
            f[i]=min(f[i],f[j]+(m+sx[i]-sx[j])*(sum-sy[j]));
        }
    }*/
    r=1;
    /*for(i=1;i<=n;i++) {
        while(l<r-1&&Y(i,Q[l])>=Y(i,Q[l+1])) l++;
        j=Q[l];
        printf("%d\n",j);
        f[i]=Y(i,j)+m*sum+sx[i]*sum;
        while(l<r-1&&cover(Q[r-2],Q[r-1],i)) r--;
        Q[r++]=i;
    }*/
    for(i=1;i<=n;i++) {
        int ll=l,rr=r-1;
        while(ll<rr) {
            int mid=(ll+rr)>>1;
            if(check(Q[mid],Q[mid+1],i)) ll=mid+1;
            else rr=mid; 
        }
        j=Q[ll];
        //printf("%d\n",j);
        f[i]=Y(i,j)+m*sum+sx[i]*sum;
        while(l<r-1&&cover(Q[r-2],Q[r-1],i)) r--;
        Q[r++]=i;
    }
    printf("%lld\n",f[n]);
}

 

posted @ 2018-06-20 09:08  fcwww  阅读(340)  评论(0编辑  收藏  举报