BZOJ2726 [SDOI2012]任务安排

题意

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser   autoint Logout 捐赠本站
Problem 2726. -- [SDOI2012]任务安排

2726: [SDOI2012]任务安排

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 2742   Solved: 866
[ Submit][ Status][ Discuss]

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

HINT

Source

[ Submit][ Status][ Discuss]

HOME Back
[1, 4] 0<N<=1000 0<=S<=2^8 0<=Ti<=2^8 0<=Fi<=2^8
[5, 12] 0<N<=300000 0<=S<=2^8 0<=Ti<=2^8 0<=Fi<=2^8
[13, 20] 0<N<=100000 0<=S<=2^8 -(2^8)<=Ti<=2^80<=Fi<=2^8

分析

复习了一下斜率DP。并且学会了用函数思想来分析。
\[ F[i]=\min_{0\le j<i}\{F[j]+sumT[i]*(sumC[i]-sumC[j])+S*(sumC[N]-sumC[j])\} \]
这里的转移用了名为“费用提前计算”的经典思想。

变化得到一次函数:
\[ F[j]=(S+sumT[i])*sumC[j]+F[i]-sumT[i]*sumC[i]-S*sumC[N] \]
显然是要在\((sumC[j],F[j])\)组成的点的平面中找一条斜率为\(S+sumT[i]\)的直线过这些点中的一个,使得截距最小。

\(sumC[j],F[j]\)单调递增,维护下凸包即可。但是由于这题有负时间,所以要在单调队列上二分。

时间复杂度\(O(n\log n)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;

co int N=3e5+1;
ll sumt[N],sumc[N],f[N];
int q[N],n,s,l,r;
int binary_search(int i,int k){
    if(l==r) return q[l];
    int L=l,R=r;
    while(L<R){
        int mid=L+R>>1;
        if(f[q[mid+1]]-f[q[mid]]<=k*(sumc[q[mid+1]]-sumc[q[mid]])) L=mid+1;
        else R=mid;
    }
    return q[L];
}
int main(){
    read(n),read(s);
    for(int i=1;i<=n;++i)
        sumt[i]=sumt[i-1]+read<int>(),sumc[i]=sumc[i-1]+read<int>();
    l=r=1,q[1]=0;
    for(int i=1;i<=n;++i){
        int p=binary_search(i,s+sumt[i]);
        f[i]=f[p]-(s+sumt[i])*sumc[p]+sumt[i]*sumc[i]+s*sumc[n];
        while(l<r&&(f[q[r]]-f[q[r-1]])*(sumc[i]-sumc[q[r]])>=(f[i]-f[q[r]])*(sumc[q[r]]-sumc[q[r-1]])) --r;
        q[++r]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10732903.html
今日推荐