[bzoj2726][DP]任务安排

123 篇文章 1 订阅

Description

机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3…N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Ci。请确定一个分组方案,使得总费用最小。

Input

第一行两个整数,N,S。 接下来N行每行两个整数,Ti,Ci。

Output

一个整数,为所求的答案。

Sample Input

5 1

1 3

3 2

4 3

2 3

1 4

Sample Output

153

题解

设t[i]表示t的前缀和 c[i]表示f的前缀和
首先dp方程给出
f[i]=min(f[j]+t[i](c[i]c[j])+S(c[n]c[j])) f [ i ] = m i n ( f [ j ] + t [ i ] ∗ ( c [ i ] − c [ j ] ) + S ∗ ( c [ n ] − c [ j ] ) )
此处影响释放给了后面的任务
大力斜率优化,可以发现在 j<k j < k

f[j]f[k]c[j]c[k]<t[i]+S f [ j ] − f [ k ] c [ j ] − c [ k ] < t [ i ] + S

k比j优秀
于是维护一个下凸壳
观察到t[i]没有单调性,不能直接单调队列
我们二分出第一个左边线段斜率小于 S+t[i] S + t [ i ] ,右边线段斜率大于 S+t[i] S + t [ i ] 的点
这个点就是最佳决策点

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL f[310000],c[310000],t[310000],S;
int n;
double slop(int j,int k){return (double)(f[j]-f[k])/(c[j]-c[k]);}
int li[310000],head,tail;
int fdans(LL gg)
{
    int l=head,r=tail;
    while(l<r)
    {
        int mid=(l+r)/2;
        if((f[li[mid]]-f[li[mid+1]])>gg*(c[li[mid]]-c[li[mid+1]]))l=mid+1;
    //    if(slop(li[mid],li[mid+1])<gg)l=mid+1;
        else r=mid;
    }
    return li[l];
}
int main()
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    scanf("%d%lld",&n,&S);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&t[i],&c[i]),t[i]+=t[i-1],c[i]+=c[i-1];
    f[0]=0;
    li[1]=0;head=tail=1;
    for(int i=1;i<=n;i++)
    {
        int p=fdans(t[i]+S);
        f[i]=f[p]+t[i]*(c[i]-c[p])+S*(c[n]-c[p]);
        while(head<tail && (f[li[tail-1]]-f[li[tail]])*(c[i]-c[li[tail]])<=(f[i]-f[li[tail]])*(c[li[tail-1]]-c[li[tail]]))tail--;
        li[++tail]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值