#斜率优化,单调队列,动态规划#poj 1180 codevs 2212 洛谷 2365 loj 10185 任务安排

PS:CH 5A01

题目

机器上有 N N N个需要处理的任务,这些任务被标号为 1 1 1 N N N,顺序不能变。这 N N N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第 i i i个任务单独完成所需的时间是 T i T_i Ti。在每批任务开始前,机器需要启动时间 S S S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 F i F_i Fi。请确定一个分组方案,使得总费用最小。


分析

首先按照费用提前计算的思想,最后可以得到状态转移方程
f [ i ] = min ⁡ { f [ j ] + s u m t [ i ] ∗ ( s u m c [ i ] − s u m c [ j ] ) + S ∗ ( s u m c [ n ] − s u m c [ j ] ) } O ( n 2 ) f[i]=\min\{f[j]+sumt[i]*(sumc[i]-sumc[j])+S*(sumc[n]-sumc[j])\}O(n^2) f[i]=min{f[j]+sumt[i](sumc[i]sumc[j])+S(sumc[n]sumc[j])}O(n2)
把仅与 i i i有关的单独提取出来可以得到
f [ i ] = min ⁡ { f [ j ] − ( s + s u m t [ i ] ) ∗ s u m c [ j ] } + s u m t [ i ] ∗ s u m c [ i ] + S ∗ s u m c [ n ] f[i]=\min\{f[j]-(s+sumt[i])*sumc[j]\}+sumt[i]*sumc[i]+S*sumc[n] f[i]=min{f[j](s+sumt[i])sumc[j]}+sumt[i]sumc[i]+Ssumc[n]
把有关 j j j的值看作变量其它当作常量得到
f [ j ] = f [ j ] − ( s + s u m t [ i ] ) ∗ s u m c [ j ] − s u m t [ i ] ∗ s u m c [ i ] − S ∗ s u m c [ n ] f[j]=f[j]-(s+sumt[i])*sumc[j]-sumt[i]*sumc[i]-S*sumc[n] f[j]=f[j](s+sumt[i])sumc[j]sumt[i]sumc[i]Ssumc[n]
可以发现这是斜率优化,在本题维护的是下凸壳,所以可以用单调队列解决(斜率满足单调性)


代码

#include <cstdio>
typedef long long ll; int n,s,q[300001];
ll f[300001],st[300001],sc[300001];
ll in(){
	ll ans=0; int f=1; char c=getchar();
	while ((c<48||c>57)&&c!='-') c=getchar();
	if (c=='-') c=getchar(),f=-f;
	while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
	return ans*f;
}
int main(){
	n=in(); s=in(); q[1]=0;
	for (int i=1;i<=n;i++)
		st[i]=st[i-1]+in(),sc[i]=sc[i-1]+in();
	f[0]=0; int l=1,r=1;
	for (int i=1;i<=n;i++){
		while (l<r&&(f[q[l+1]]-f[q[l]])<=(s+st[i])*(sc[q[l+1]]-sc[q[l]])) l++;//队头可以更优
		f[i]=f[q[l]]-(s+st[i])*sc[q[l]]+st[i]*sc[i]+s*sc[n];//dp
		while (l<r&&(f[q[r]]-f[q[r-1]])*(sc[i]-sc[q[r]])>=(f[i]-f[q[r]])*(sc[q[r]]-sc[q[r-1]])) r--;//队尾不满足单调递增
		q[++r]=i; 
	}
	return !printf("%lld",f[n]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值