• BZOJ 2726 [SDOI2012] 任务安排


    题解

    转移方程与我的上一篇题解一样 : $S imes sumC_j  + F_j = sumT_i imes sumC_j + F_i - S imes sumC_N$。

    分离成:$S imes sumC_j  + F_j = sumT_i imes sumC_j + F_i - S imes sumC_N$

    不同的是, 时间可能为 负数(出题人解释:不要把时间看的这么狭义。

    所以$sumT_i$不是递增。

    所以我们不能在队首弹出斜率比 $sumT_i$小的数, 只能用一个数据结构来维护并查询, 我当然是用了好玩的set

    但是队尾还是需要维护下凸壳。

    有一个坑点:用叉积来弹出队尾可能爆longlong, 开double可以过QAQ

    代码

     1 #include<cstring>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<set>
     6 #define rd read()
     7 #define rep(i,a,b) for( int i = (a); i <= (b); ++i)
     8 #define per(i,a,b) for( int i = (a); i >= (b); --i)
     9 using namespace std;
    10 #define ll long long
    11 typedef pair<double, ll>P;
    12 
    13 const ll N = 1e6;
    14 const ll inf = 1e18;
    15 const double eps = 1e-6;
    16 
    17 ll S, sumT[N], sumC[N], q[N], n;
    18 ll f[N];
    19 
    20 set<P>st;
    21 
    22 ll read() {
    23     ll X = 0, p = 1; char c = getchar();
    24     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
    25     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
    26     return X * p;
    27 }
    28 
    29 ll cross(ll a, ll b, ll c) { //叉积
    30     ll ax = sumC[a], bx = sumC[b], cx = sumC[c];
    31     ll ay = f[a], by = f[b], cy = f[c];
    32     ll x = bx - ax, y = by - ay, xx = cx - ax, yy = cy - ay;
    33     if(fabs(1LL * x * yy - 1LL * xx * y) < eps) return 0;
    34     return (long double)x * yy > (long double)xx * y;
    35 }
    36     
    37 double calc(ll a, ll b) {
    38     ll ax = sumC[a], bx = sumC[b];
    39     ll ay = f[a], by = f[b];
    40     if(bx - ax == 0) return by > ay ? inf : -inf;
    41     else return 1.0 * (by - ay) / (bx - ax);
    42 }
    43 
    44 int main()
    45 {
    46     n = rd; S = rd;
    47     rep(i, 1, n) {
    48         ll t = rd, c = rd;
    49         sumT[i] = sumT[i - 1] + t;
    50         sumC[i] = sumC[i - 1] + c;
    51     }
    52     ll l = 1, r = 1;
    53     q[1] = f[0] = 0;
    54     set<P>::iterator it;
    55     st.insert(P(-inf, 0));
    56     rep(i, 1, n) {
    57         double k = S + sumT[i];
    58         P fd = P(k, 0);
    59         it = st.lower_bound(fd);//查找最小的斜率比sumT[i]大的
    60         it--;
    61         ll p = (*it).second;
    62         f[i] = f[p] + 1LL * sumT[i] * (sumC[i] - sumC[p]) + 1LL * S * (sumC[n] - sumC[p]);
    63         while(l < r && cross(q[r - 1], q[r], i) == 0) {
    64             st.erase(P(calc(q[r - 1], q[r]), q[r]));
    65             r--;
    66         }
    67         q[++r] = i;
    68         st.insert(P(calc(q[r - 1], q[r]), i));
    69     }
    70     printf("%lld
    ", f[n]);
    71     fclose(stdin); fclose(stdout);
    72 }
    View Code
  • 相关阅读:
    day08超市商品库存案例
    day07
    day06_03
    day06_02
    day06_01
    最简单的库存管理java案例
    Day05_homework
    方法的使用注意事项
    day05
    冒泡排序
  • 原文地址:https://www.cnblogs.com/cychester/p/9502178.html
Copyright © 2020-2023  润新知