1. 程式人生 > >【BZOJ2726】[SDOI2012]任務安排 斜率優化+cdq分治

【BZOJ2726】[SDOI2012]任務安排 斜率優化+cdq分治

時間 斜率 bool print pan i+1 main 最小 可能

【BZOJ2726】[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個任務的最小費用,但是做完當前任務的時間對後面的任務也會造成影響,所以我們提前應計算費用,不難列出方程:

設st表示T的前綴和,sf表示F的前綴和,所以有:

$f[i]=\min \{ f[j]+(st[i]-st[j]+S)*(sf[n]-sf[j])\}$

移個項顯然就變成了斜率優化的形式。不過坑的地方是,T可能是負數,所以斜率不是單調的,所以用cdq分治即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=300010;
typedef long long ll;
typedef long double ld;
int n;
ll S;
struct node
{
	int x,org,k;
	ll y,f;
}s[maxn],p[maxn];
int q[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
bool cmpk(const node &a,const node &b)
{
	return a.k>b.k;
}
bool cmpo(const node &a,const node &b)
{
	return a.org<b.org;
}
inline ld slope(int a,int b)
{
	if(s[a].x==s[b].x)	return (s[b].y>=s[a].y)?(1e20):(-1e20);
	else	return ld(s[b].y-s[a].y)/(s[b].x-s[a].x);
}
void solve(int l,int r)
{
	if(l==r)
	{
		s[l].y=(ll)s[l].x*(s[l].k-S)-s[l].f;
		return ;
	}
	register int mid=(l+r)>>1,i,h1=l,h2=mid+1;
	for(i=l;i<=r;i++)
	{
		if(s[i].org<=mid)	p[h1++]=s[i];
		else	p[h2++]=s[i];
	}
	for(i=l;i<=r;i++)	s[i]=p[i];
	solve(l,mid);
	register int h=1,t=0;
	for(i=l;i<=mid;i++)
	{
		while(h<t&&slope(q[t],i)>=slope(q[t-1],q[t]))	t--;
		q[++t]=i;
	}
	for(i=mid+1;i<=r;i++)
	{
		while(h<t&&slope(q[h],q[h+1])>=s[i].k)	h++;
		s[i].f=min(s[i].f,s[q[h]].f+s[q[h]].x*(s[i].k-s[q[h]].k+S));
	}
	solve(mid+1,r);
	h1=l,h2=mid+1;
	for(i=l;i<=r;i++)
	{
		if(h1<=mid&&(h2>r||s[h1].x<s[h2].x))	p[i]=s[h1++];
		else	p[i]=s[h2++];
	}
	for(i=l;i<=r;i++)	s[i]=p[i];
}
int main()
{
	n=rd(),S=rd();
	int i;
	for(i=1;i<=n;i++)	s[i].k=s[i-1].k+rd(),s[i-1].x=rd(),s[i].org=i;
	for(i=n-1;i>=0;i--)	s[i].x+=s[i+1].x;
	for(i=1;i<=n;i++)	s[i].f=s[0].x*(s[i].k+S);
	sort(s+1,s+n+1,cmpk);
	solve(1,n);
	sort(s+1,s+n+1,cmpo);
	printf("%lld",s[n].f);
	return 0;
}

【BZOJ2726】[SDOI2012]任務安排 斜率優化+cdq分治