【bzoj2726】[SDOI2012]任务安排

26 篇文章 0 订阅
6 篇文章 0 订阅

首先暴力dp应该是很简单的

dp[i]=min(dp[j]+cost[i]*(T[i]-T[j]+S)) (j>i)

本来简单的斜率优化因为脑洞大的出题人一句时间可以是负的变成了cdq维护dp

但比较好的一点是可以先把所有决策点加入凸包,在枚举询问(按斜率排序(T[pos]))在凸包上跑答案。

#include <bits/stdc++.h>
#define gc getchar()
#define N 500009
#define mid (l+r>>1)
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,s,t[N],f[N],T[N],F[N],dp[N],top;
//X(i)=F[i],Y(i)=dp[j]-F[n]*T[j]+F[j]*T[j]-s*F[j],a(i)=T[i]
//dp[i]=min{X(i)*-a(i)+Y(i)}
//Y(i)=a(i)*X(i)+p
struct node
{
	ll k,x,y,pos,pd;
	node(ll pos=0):pos(pos)
	{
		k=T[pos];
	}
	void get()
	{
		x=F[pos],y=dp[pos]-F[n]*T[pos]+F[pos]*T[pos]-s*F[pos];
	}
	bool operator <(const node &rhs) const
	{
		return k<rhs.k;
	}
}q[N],now[N],sta[N];
bool cmp(const node &lhs,const node &rhs)
{
	return lhs.x<rhs.x||(lhs.x==rhs.x&&lhs.y<rhs.y);
}
ll read()
{
	ll x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	ll s=ch-'0';
	while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
	return s*x;
}
ll up(const node &a,const node &b)
{
	return a.y-b.y;
}
ll down(const node &a,const node &b)
{
	return a.x-b.x;
}
void solve(ll l,ll r)
{
	if (l==r)
	{
		q[l].get();
		return;
	}
	ll l1=l,l2=mid+1;
	for (ll i=l;i<=r;i++)
		if (q[i].pos<=mid) now[l1++]=q[i];
		else now[l2++]=q[i];
	for (ll i=l;i<=r;i++) q[i]=now[i];
	solve(l,mid);
	top=0;
	for (ll i=l;i<=mid;i++)//k is increasing 
	{
		while (top>=2&&up(q[i],sta[top])*down(sta[top],sta[top-1])<up(sta[top],sta[top-1])*down(q[i],sta[top])) top--;
		sta[++top]=q[i];
	}
	ll j=1;
	for (ll i=mid+1;i<=r;i++)
	{
		while (j<top&&q[i].k*down(sta[j],sta[j+1])<up(sta[j],sta[j+1])) j++;
		dp[q[i].pos]=min(dp[q[i].pos],sta[j].y-sta[j].x*q[i].k+F[n]*(T[q[i].pos]+s));
	}
	solve(mid+1,r);
	l1=l,l2=mid+1;
	for (ll i=l;i<=r;i++)
		if ((cmp(q[l1],q[l2])||(l2>r))&&l1<=mid) now[i]=q[l1++];
		else now[i]=q[l2++];
	for (ll i=l;i<=r;i++) q[i]=now[i];
}
int main()
{
	n=read(),s=read();
	for (ll i=1;i<=n;i++)
		t[i]=read(),f[i]=read(),dp[i]=inf;
	for (ll i=1;i<=n;i++)
		T[i]=T[i-1]+t[i],F[i]=F[i-1]+f[i];
	for (ll i=0;i<=n;i++) q[i]=node(i);
	sort(q,q+n+1);
	solve(0,n);
	printf("%lld\n",dp[n]);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值