zoukankan      html  css  js  c++  java
  • BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

     考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关的量只有t = dp(j) - F(i) * T(j) , 我们要最小化它. dp(j)->y, T(j)->x, 那么y = F(i) * x + t, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(假如时间为非负数用单调队列就行了)....或者cdq分治. O(N log N)平衡树维护大家都应该会...cdq分治就是对于[l, r), m=(l+r)/2, 处理[m, r)的dp值对[l, m)dp值的贡献(这道题是从后往前dp). 具体就是暴力建[m, r)的凸包, 然后[l, m)的按斜率排序, 依次询问. 预处理一下, 时间复杂度就是O(N log N)了, 空间复杂度是O(N).

    -------------------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 300009;
     
    int N, S, V[maxn], q[maxn], stk[maxn], T[maxn], F[maxn];
    ll dp[maxn];
     
    void Init() {
    scanf("%d%d", &N, &S);
    for(int i = 0; i < N; i++) {
    scanf("%d%d", T + i, F + i);
    q[i] = N - i - 1;
    }
    T[N] = F[N] = 0;
    for(int i = N; i--; )
    T[i] += T[i + 1], F[i] += F[i + 1];
    }
     
    bool chk(int a, int b, int c) {
    int xl = T[b] - T[a], xr = T[c] - T[b];
    ll yl = dp[b] - dp[a], yr = dp[c] - dp[b];
    return ((xl < 0) ^ (xr < 0)) ? yl * xr <= yr * xl : yl * xr >= yr * xl;
    }
     
    bool Jud(int a, int b, int k) {
    ll x = T[b] - T[a], y = dp[b] - dp[a];
    return x < 0 ? y > x * k : y < x * k;
    }
     
    ll calc(int x, int y) {
    return dp[y] + ll(F[x]) * (T[x] - T[y] + S);
    }
     
    // [l, r)
    void cdq(int l, int r) {
    if(l + 1 == r) return;
    int m = (l + r) >> 1;
    int ql = l, qr = m;
    for(int i = l; i < r; i++)
    q[i] < m ? V[ql++] = q[i] : V[qr++] = q[i];
    for(int i = l; i < r; i++) q[i] = V[i];
    cdq(m, r);
    int h = 0, t = -1;
    for(int i = m; i < r; i++) {
    while(t > 0 && chk(stk[t - 1], stk[t], q[i])) t--;
    stk[++t] = q[i];
    }
    for(int i = l; i < m; i++) {
    while(h < t && Jud(stk[h], stk[h + 1], F[q[i]])) h++;
    dp[q[i]] = min(dp[q[i]], calc(q[i], stk[h]));
    }
    cdq(l, m);
    ql = l, qr = m;
    for(int i = l; i < r; i++) if(ql >= m) {
    V[i] = q[qr++];
    } else if(qr >= r) {
    V[i] = q[ql++];
    } else
    V[i] = T[q[ql]] < T[q[qr]] ? q[ql++] : q[qr++];
    for(int i = l; i < r; i++) q[i] = V[i];
    }
     
    void Work() {
    for(int i = 0; i < N; i++)
    dp[i] = ll(F[i]) * (T[i] + S);
    cdq(0, N);
    printf("%lld ", dp[0]);
    }
     
    int main() {
    Init();
    Work();
    return 0;
    }

    -------------------------------------------------------------------------------------------------

    2726: [SDOI2012]任务安排

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 660  Solved: 171
    [Submit][Status][Discuss]

    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

    HINT

    Source

  • 相关阅读:
    [Codeforces Round #498 (Div. 3)] -F. Xor-Paths (折半搜索)
    Best Reward [HDU
    [Educational Codeforces Round 72] A. Creating a Character (简单数学)
    [Codeforces Round #624 (Div. 3)] -E. Construct the Binary Tree (构造二叉树)
    [Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)] -D. Present(异或性质,按位拆分,双指针)
    [Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)] -D. Present(异或性质,按位拆分,树桩数组)
    [Educational Codeforces Round 83 ] E. Array Shrinking
    [AtCoder Beginner Contest 158]
    [CodeCraft-20 (Div. 2)]- E. Team Building (状压DP)
    HDU 3308 LCIS (线段树区间合并)
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5184251.html
Copyright © 2011-2022 走看看