题意
![](image/logo.png)
F.A.Qs | Home | Discuss | ProblemSet | Status | Ranklist | Contest | 入门OJ | ModifyUser autoint | Logout | 捐赠本站 |
---|
2726: [SDOI2012]任务安排
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
1 3
3 2
4 3
2 3
1 4
Sample Output
153
HINT
Source
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
[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_{0le 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(nlog 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
",f[n]);
return 0;
}