BZOJ2726 SDOI2012 任务安排
作者:互联网
题目
机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
思路
首先显然是\(dp\)划分状态。
\[
dp[i]=min(dp[j]+t[i]*(f[i]-f[j])+s*f[n]-s*f[j])
\]
不难看出可以斜率优化。
然而不知道出题人怎么想的,时间竟然可以出现负数,这样对于\(x\)不单调的斜率优化,就只能用CDQ分治维护凸包。
具体而言,就是和惯常的CDQ分治一样,分别将\([l,mid]\),\([mid+1,r]\)区间排序,\([l,mid]\)建一个凸包,回答\([mid+1,r]\)的询问。
一个while打成if调了一个晚上
代码
#include<bits/stdc++.h>
#define M 300005
#define LL long long
using namespace std;
LL t[M],f[M],dp[M],s;
int n,qcnt,tcnt,top;
struct node{
LL x,y;
bool operator < (const node& res)const{
if(x!=res.x)return x<res.x;
return y>res.y;
}
}Q[M],stk[M],to[M];
bool cmp(node a,node b,node c){
return (long double)(c.y-a.y)*(a.x-b.x)<=(long double)(a.y-b.y)*(c.x-a.x);
}
LL calc(int cur,int i){
return (long double)stk[cur].y-(long double)t[to[i].y]*stk[cur].x+(long double)t[to[i].y]*f[to[i].y]+(long double)s*f[n];
}
void CDQ(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
CDQ(l,mid);qcnt=0;
for(int i=l;i<=mid;i++)
Q[++qcnt]=(node){f[i],dp[i]-s*f[i]};
sort(Q+1,Q+qcnt+1);top=0;
for(int i=1;i<=qcnt;i++){
while(top>1&&cmp(stk[top],stk[top-1],Q[i]))top--;
stk[++top]=Q[i];
}
tcnt=0;
for(int i=mid+1;i<=r;i++)
to[++tcnt]=(node){t[i],i};
sort(to+1,to+tcnt+1);
int cur=1;
for(int i=1;i<=tcnt;i++){
while(cur<top&&calc(cur+1,i)<calc(cur,i))cur++;
dp[to[i].y]=min(dp[to[i].y],calc(cur,i));
}
CDQ(mid+1,r);
}
int main(){
memset(dp,60,sizeof(dp));dp[0]=0;
scanf("%d%lld",&n,&s);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&t[i],&f[i]);
t[i]+=t[i-1];f[i]+=f[i-1];
}
CDQ(0,n);
printf("%lld\n",dp[n]);
return 0;
}
标签:node,BZOJ2726,top,安排,SDOI2012,mid,任务,stk,dp 来源: https://www.cnblogs.com/zryabc/p/11232182.html