bzoj 2726: [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


這題完成的時間是有負數的,但是似乎費用係數Fi沒負數。

明明兩個輸入的描述是一樣的。。也不知道出題人在想什麼。。或者說畢竟SDOI麼

我們考慮從後往前轉移 F,T均爲後綴和

f[i]=min(f[j]+(Ti-Tj+S)*Fi)

大概這樣一個轉移式。

假設j<k,j比k優,

即f[j]+(Ti-Tj+S)*Fi<f[k]+(Ti-Tk+S)*Fi

移項後得

f[j]-f[k]<Fi*(Tj-Tk)

因爲T不是單調的所以沒辦法做除法。

我們考慮cdq分治

假設當前區間是[l,r]

則先把[mid,r]的答案處理出來,然後把[mid,r]中的T按照升序排序

這樣就保證了T的單調性,暴力維護出凸殼

然後對於[l,mid],因爲F是單調的,所以直接順着凸殼掃過去找到最優轉移位置就可以了

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct quest
{
	long long t,f;
	long long fx;
	int p;
}a[300005],b[300005];
inline bool cmp(quest x,quest y)
{
	return x.p<y.p;
}
int q[300005];
long long f[300005];
long long s;
inline bool check(int x,int y,int z)
{
	return (a[z].t-a[y].t)*(a[y].fx-a[x].fx)>=(a[z].fx-a[y].fx)*(a[y].t-a[x].t);
}
inline bool getk(int x,int y,long long z)
{
	return (a[y].fx-a[x].fx)<z*(a[y].t-a[x].t);
}
inline long long calc(int x,int i)
{
	return a[x].fx+a[i].f*(a[i].t-a[x].t+s);
}
inline void solve(int ll,int rr)
{
	if(ll==rr-1)
	{
		return ;
	}
	int mid=(ll+rr)/2;
	solve(mid,rr);
	int i;
	int l=1,r=0;
	for(i=rr-1;i>=mid;i--)
	{
		while(r>1&&check(q[r-1],q[r],i))
			r--;
		r++;
		q[r]=i;
	}
	for(i=mid-1;i>=ll;i--)
	{
		while(l<r&&getk(q[l],q[l+1],a[i].f))
			l++;
		a[i].fx=min(a[i].fx,calc(q[l],i));
	}
	solve(ll,mid);
	int d1=rr-1,d2=mid-1;
	for(i=rr-1;i>=ll;i--)
	{
		if(d1<=mid-1)
		{
			b[i]=a[d2];
			d2--;
		}
		else if(d2<=ll-1)
		{
			b[i]=a[d1];
			d1--;
		}
		else
		{
			if(a[d2].t<a[d1].t||a[d2].t==a[d1].t)
			{
				b[i]=a[d2];
				d2--;
			}
			else
			{
				b[i]=a[d1];
				d1--;
			}
		}
	}
	for(i=ll;i<=rr-1;i++)
		a[i]=b[i];
}
int main()
{
	int n;
	scanf("%d%lld",&n,&s);
	int i;
	for(i=1;i<=n;i++)
	{
		scanf("%lld%lld",&a[i].t,&a[i].f);
		a[i].p=i;
	}
	for(i=n;i>=1;i--)
	{
		a[i].t=a[i+1].t+a[i].t;
		a[i].f=a[i+1].f+a[i].f;
		a[i].fx=a[i].f*(a[i].t+s);
	}
	solve(1,n+1);
	sort(a+1,a+1+n,cmp);
	printf("%lld\n",a[1].fx);
	return 0;
}


發佈了406 篇原創文章 · 獲贊 16 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章