码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2726 [SDOI2012]任务安排

时间:2019-12-17 22:31:50      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:pre   任务   std   read   getc   bre   while   题目   strong   

题目链接

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)\},j\in[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]任务安排

标签:pre   任务   std   read   getc   bre   while   题目   strong   

原文地址:https://www.cnblogs.com/wxyww/p/bzoj2726.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!