bzoj2726 [SDOI2012]任务安排

Posted wxyww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2726 [SDOI2012]任务安排相关的知识,希望对你有一定的参考价值。

题目链接

problem

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

solution

f[i]表示前i个物品进行分组的最小花费。
下面的(c_i)表示题目描述中(c_i)的前缀和,(t_i)表示题目描述中(t_i)的前缀和。

考虑(n^2)做法

由于每次分组都会导致后面的时刻后移,所以花费系数就是(c_n-c_j)

(f_i=min{f_j+(c_n-c_j)(t_i-t_j+S)},jin[0,i))

(n^2)转移即可。

考虑优化成(nlogn)

将上面的式子展开并处理一下:

(f_i=min{f_j+c_nt_i-c_nt_j+c_nS-c_jt_i+c_jt_j-c_jS}\ =min{t_i(c_n-c_j)+f_j-c_nt_j+c_nS+c_jt_j-c_jS})

然后就很斜率优化了。。

可是(t_i)并没有单调性

所以不能直接单调队列优化。可以用一个单调栈维护凸包,然后查询的时候就在上面二分即可。

code

/*
* @Author: wxyww
* @Date:   2019-12-17 19:59:58
* @Last Modified time: 2019-12-17 21:13:05
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 300100;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1; c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0'; c = getchar();
    }
    return x * f;
}
ll c[N],t[N],n;
ll S;

struct node {
    ll k,b;
}q[N];

int top;

void ins(ll k,ll b) {
    while(top >= 1) {
        ll k2 =  q[top].k,k3 = q[top - 1].k,b2 = q[top].b,b3 = q[top - 1].b;
        if((b2 - b) * (k2 - k3) <= (b3 - b2) * (k - k2)) --top;
        else break;
    }
    q[++top] = (node){k,b};
}
inline ll calc(ll k,ll b,ll x) {
    return k * x + b;
}
ll get(ll x) {
    int l = 1,r = top;
    int ans = 0;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(calc(q[mid].k,q[mid].b,x) > calc(q[mid - 1].k,q[mid - 1].b,x)) r = mid - 1;
        else ans = mid,l = mid + 1;
    }
    return calc(q[ans].k,q[ans].b,x);
}

int main() {
    n = read(),S = read();
    for(int i = 1;i <= n;++i) {
        t[i] = t[i - 1] + read();c[i] = c[i - 1] + read();
    }
    q[0].k = c[n],q[0].b = S * c[n];
    ins(c[n],S * c[n]);
    ll now = 0;
    for(int i = 1;i <= n;++i) {
        now = get(t[i]);
        ins(c[n] - c[i],now + c[i] * t[i] - c[n] * t[i] + S * (c[n] - c[i]));
    }
    cout<<now;
    return 0;
}

以上是关于bzoj2726 [SDOI2012]任务安排的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2726: [SDOI2012]任务安排 [斜率优化DP 二分 提前计算代价]

bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)

bzoj 2726: [SDOI2012]任务安排

bzoj2726 [SDOI2012]任务安排

BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

BZOJ2726 [SDOI2012]任务安排 斜率优化 + cdq分治