任务安排「SDOI2012」

题意

有一个数列,每个元素均有一个完成耗时\(t_i\)与完成耗费\(f_i\),每个元素的耗费等于其完成时刻乘以完成耗费。可以将这些元素分为任意组,每一组的元素完成时刻一样。每一组都会有一个固定的额外时间耗费\(s\)。数据范围\(3*10^5\)


思路

首先推出状态转移方程\(dp[i]=min(dp[j]+s*(sumf[n]-sumf[j])+sumt[i]*(sumf[i]-sumf[j]))\)

拆开可以得到斜率

\(\frac{dp[j]-dp[k]}{sumf[j]-sumf[k]}>s+sumt[i]\)

然而斜率不具有单调性,因此考虑\(CDQ\)分治。

左侧直接更新右侧即可。


代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

	template<typename T>inline void read (T &x) {
		x=0;T f=1;char c=getchar();
		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
		x*=f;
	}

	template<typename T>inline void write (T x) {
		if (x<0) putchar('-'),x*=-1;
		if (x>=10) write(x/10);
		putchar(x%10+'0');
	}

}

using namespace StandardIO;

namespace Project {
	#define int long long
	
	const int N=300300;
//	const int INF=2147483647;
	
	int n,s,head,tail;
	int t[N],f[N],dp[N];
	struct node {
		int id;
		int x,y;
		node () {}
		node (int _x,int _y) : x(_x),y(_y) {}
		friend node operator + (const node &x,const node &y) {
			return node(x.x+y.x,x.y+y.y);
		}
		friend node operator - (const node &x,const node &y) {
			return node(x.x-y.x,x.y-y.y);
		}
		friend int operator * (const node &x,const node &y) {
			return x.x*y.y-x.y*y.x;
		}
	} w[N],queue[N],tmp[N];
	
	inline bool cmpid (const node &x,const node &y) {
		return t[x.id]<t[y.id];
	}
	inline bool cmpx (const node &x,const node &y) {
		return (x.x==y.x)?(x.y<y.y):(x.x<y.x);
	}
	inline double slope (node x,node y) {
		return static_cast<double>(x.y-y.y)/static_cast<double>(x.x-y.x);
	}
	void merge1 (int l,int r) {
		int mid=(l+r)>>1,ptr_l=l,ptr_r=mid+1;
		for (register int i=l; i<=r; ++i) {
			if (w[i].id<=mid) tmp[ptr_l++]=w[i];
			else tmp[ptr_r++]=w[i];
		}
		for (register int i=l; i<=r; ++i) w[i]=tmp[i];
	}
	void merge2 (int l,int r) {
		int mid=(l+r)>>1,ptr_l=l,ptr_r=mid+1;
		for (register int i=l; i<=r; ++i) {
			if (ptr_l<=mid&&(ptr_r>r||cmpx(w[ptr_l],w[ptr_r]))) tmp[ptr_l++]=w[i];
			else tmp[ptr_r++]=w[i];
		}
		for (register int i=l; i<=r; ++i) w[i]=tmp[i];
	}
	void CDQ (int l,int r) {
		if (l==r) return w[l].x=f[w[l].id],w[l].y=dp[w[l].id],void();
		int mid=(l+r)>>1;merge1(l,r),CDQ(l,mid),head=1,tail=0;
		for (register int i=l; i<=mid; ++i) {
			while (head<tail&&(queue[tail]-queue[tail-1])*(w[i]-queue[tail-1])<0) --tail;
			queue[++tail]=w[i];
		}
		for (register int i=mid+1; i<=r; ++i) {
			while (head<tail&&slope(queue[head+1],queue[head])<s+t[w[i].id]) ++head;
			dp[w[i].id]=min(dp[w[i].id],dp[queue[head].id]+s*(f[n]-f[queue[head].id])+t[w[i].id]*(f[w[i].id]-f[queue[head].id]));
		}
		CDQ(mid+1,r),merge2(l,r);
	}

	inline void MAIN () {
		read(n),read(s);
		for (register int i=1; i<=n; ++i) read(t[i]),read(f[i]),t[i]+=t[i-1],f[i]+=f[i-1],w[i].id=i;
		sort(w+1,w+n+1,cmpid),memset(dp,0x3f,sizeof(dp)),dp[0]=0,CDQ(0,n);
		write(dp[n]);
	}
	
	#undef int
}

int main () {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	Project::MAIN();
}
posted @ 2019-08-19 20:14  Ilverene  阅读(126)  评论(0编辑  收藏  举报