BZOJ:2726: [SDOI2012]任务安排(斜率优化)

题目

你有n个任务和一台机器,第i个任务完成时间是s[i],带来的费用是它的完成时间*费用系数f[i]。
每次启动机器需要时间S,可以将几个任务分成一组,这样只需要启动一次机器,但是所有任务的完成时间都将被计算为最后一个任务完成的时间。
注意计算等待时间!!!
现在你需要使费用最小。
时间可以为负数
0 < N<=300000 0<=S<=2^8 -(2^8)<=Ti<=2^8 0<=Fi<=2^8

分析

朴素方程

f(i,j)表示将前i个元素分成j组的最小费用。
f(i,j)=min{ f(k,j-1) + ( s * j + sumT [i] )( sumF[i]-sumF[k]) | 0<=k< I }

sumT表示T的前缀和
sumF表示F的前缀和

时间复杂度O(n^3)
空间复杂度O(n^2)

会炸的

进阶版方程

假设我们分好了组:
第i组完成的时间是ai+i*s,第i组的费用系数和是bi。
Ans=(a1+s)*b1+(a2+2*s)*b2+…+(am+m*s)*bm
集中注意力辣!!
Ans=(a1*b1+a2*b2+…+am*bm)+(s*b1+s*2*b2+..s*m*bm)
=(a1*b1+a2*b2+…+am*bm)+s*( (b1+…+bm-1+bm) +…+(bm+1+bm)+(bm))
其中a其实是原T的前缀和,b那一堆可以处理成后缀和。
那么令sumT为T的前缀和,sumrF为F的后缀和,有转移方程如下:
F(i)=min{f(j)+sumT(i)*( sumrF(j+1)-sumrF(i+1) )+s*sumrF(j+1)|0<=j

斜率优化

define st sumT
define sf sumrF
令t1<=t2< I,则当t2为更优决策时,有:
F(t2)-F(t1)/(sf(t2+1)-sf(t1+1))>=-st[i]-s//sf(t2+1)-sf(t1+1))<0变号

则令y[i]=F(i),x[i]=sf(i+1)

x有单调性
所以维护下凸包即可,然后三分找答案。
注意在考虑的时候,由于X单调递减,所以所谓的往后一个元素实际上在图的位置上是往前一个元素,卡了好久哦。
这里最好用叉积(结合long doulbe),否则会炸掉

然后还可以用CDQ来做,这里我强行CDQ了一波(时间多了个log),随机数据挺快的,但是会被卡!!我的第一道CDQ啊啊啊啊,过都过不了。

代码

三分版

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
const int maxn=3e5+105;
const LL inf=1e18;
int n,s;
int t[maxn],f[maxn],st[maxn],sf[maxn];
LL d[maxn],x[maxn],y[maxn];
void Init()
{
    scanf("%d%d",&n,&
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值