bzoj2726: [SDOI2012]任务安排 斜率优化Dp+cdq分治

bzoj2726: [SDOI2012]任务安排

Description

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

Input

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

Output

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

Sample Input

5 1
1 3
3 2
4 3
2 3
1 4

Sample Output

153

分析

方程写出来
f [ i ] = m i n { f [ j ] + ( F [ n ] F [ j ] ) ( T [ i ] T [ j ] + S ) }
拆开
f [ i ] = m i n { f [ j ] + F [ j ] ( T [ j ] S ) F [ n ] T [ j ] F [ j ] T [ i ] } + F [ n ] ( T [ i ] + S )
Y [ j ] = f [ j ] + F [ j ] ( T [ j ] S ) F [ n ] T [ j ] , X [ j ] = F [ j ]
f [ i ] = m i n { Y [ j ] X [ j ] T [ i ] } + F [ n ] ( T [ i ] + S )
化成斜截式可以搞斜率优化Dp
但是出题人的脑洞是时间可以是负数。
于是只好套一个分治。
具体见bzoj1492
里面有方法。

分析

#include<cstdio>
#include<algorithm>
const int N = 5e5 + 10; const double eps = 1e-10;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1; 
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0'; return x * f;
}
int h[N], n, S; long long f[N], G;
struct data {
    long long k, x, y; int i;
    void In(int id) {k = ri(); x = ri(); i = id;}
    void Get() {y = ::f[i] + 1LL * (x - G) * k - x * S;}
    void Tra(data j) {f[i] = std::min(f[i], j.y - j.x * k + G * (S + k));}
    bool operator < (data b) {return x == b.x ? y < b.y : x < b.x;}
}p[N], q[N];
bool cmp(data a, data b) {return a.k < b.k;}
long long U(int j, int k) {return q[k].y - q[j].y;}
long long D(int j, int k) {return q[k].x - q[j].x;}
void Solve(int L, int R) {
    if(L == R) return p[L].Get();
    int m = L + R >> 1; int s = L, t = m + 1;
    for(int i = L; i <= R; ++i) p[i].i <= m ? q[s++] = p[i] : q[t++] = p[i];
    for(int i = L; i <= R; ++i) p[i] = q[i];
    Solve(L, m); int tp = 0;
    for(int i = L;i <= m; ++i) {
        for(;tp > 1 && U(h[tp - 1], h[tp]) * D(h[tp], i) > D(h[tp - 1], h[tp]) * U(h[tp], i); ) --tp;
        h[++tp] = i;
    } int j = 1;
    for(int i = m + 1; i <= R; ++i) {
        for(;j < tp && U(h[j], h[j + 1]) < p[i].k * D(h[j], h[j + 1]);) ++j;
        p[i].Tra(p[h[j]]);
    }
    Solve(m + 1, R); s = L; t = m + 1; tp = L;
    for(;s <= m && t <= R;) q[tp++] = (p[s] < p[t] ? p[s++] : p[t++]);
    for(;s <= m;) q[tp++] = p[s++]; for(;t <= R;) q[tp++] = p[t++];
    for(int i = L;i <= R; ++i) p[i] = q[i];
}
int main() {
    n = ri(); S = ri();
    for(int i = 1;i <= n; ++i) p[i].In(i), f[i] = 1e18;
    for(int i = 2;i <= n; ++i) p[i].x += p[i - 1].x, p[i].k += p[i - 1].k;
    G = p[n].x; std::sort(p + 1, p + n + 1, cmp);
    Solve(0, n); printf("%lld\n", f[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/81066151
今日推荐