[SDOI2012]任务安排

题意

<body> <center> <div style="width:90%; text-align:left"> <img src="image/logo.png"> </div> <table width="96%"> <tbody><tr align="center" class="hd" valign="top"> <th><a href="faqs.php">F.A.Qs</a></th> <th><a href="./">Home</a></th> <th><a href="./bbs.php">Discuss</a></th> <th><a href="./problemset.php">ProblemSet</a></th> <th><a href="./status.php">Status</a></th> <th><a href="./ranklist.php">Ranklist</a></th> <th><a href="./contest.php">Contest</a></th> <th><a href="http://begin.lydsy.com/JudgeOnline">入门OJ</a></th> <th><a href="./modifypage.php"><b>ModifyUser</b></a>&nbsp;&nbsp;<a href="userinfo.php?user=autoint"> <font color="red">autoint</font></a></th><th><a href="logout.php">Logout</a></th> <th><a href="./donation.php"><font color="red">捐赠本站</font></a></th> </tr> </tbody></table> </center> <title>Problem 2726. -- [SDOI2012]任务安排</title><center><h2>2726: [SDOI2012]任务安排</h2><span class="green">Time Limit: </span>10 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>128 MB<br><span class="green">Submit: </span>2742&nbsp;&nbsp;<span class="green">Solved: </span>866<br>[<a href="submitpage.php?id=2726">Submit</a>][<a href="problemstatus.php?id=2726">Status</a>][<a href="bbs.php?id=2726">Discuss</a>]</center><h2>Description</h2><div class="content"><div style="text-indent: 21pt" align="left"><span style="font-size: medium">机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。<b>注意,同一批任务将在同一时刻完成。</b>每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。</span></div></div><h2>Input</h2><div class="content"><div style="text-indent: 21pt" align="left"><span style="font-size: medium">第一行两个整数,N,S。</span></div> <div style="text-indent: 21pt" align="left"><span style="font-size: medium">接下来N行每行两个整数,Ti,Fi。</span></div></div><h2>Output</h2><div class="content"><div style="text-indent: 21pt" align="left"><span style="font-size: medium">一个整数,为所求的答案。</span></div></div><h2>Sample Input</h2> <div class="content"><span class="sampledata">5 1<br> 1 3<br> 3 2<br> 4 3<br> 2 3<br> 1 4<br> </span></div><h2>Sample Output</h2> <div class="content"><span class="sampledata">153</span></div><h2>HINT</h2> <div class="content"><p></p></div><h2>Source</h2> <div class="content"><p><a href="problemset.php?search="></a></p></div><center>[<a href="submitpage.php?id=2726">Submit</a>][<a href="problemstatus.php?id=2726">Status</a>][<a href="bbs.php?id=2726">Discuss</a>]</center><br> <a href="./"><span class="red">HOME</span></a> <a href="javascript:history.go(-1)"><span class="red">Back</span></a> </body>
[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;
}

posted on 2019-04-18 22:35  autoint  阅读(125)  评论(0编辑  收藏  举报

导航