题目
你有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,&