cychester

BZOJ 2726 [SDOI2012] 任务安排 - 斜率优化dp

题解

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

分离成:$S\times sumC_j  + F_j = sumT_i \times sumC_j + F_i - S \times 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\n", f[n]);
71     fclose(stdin); fclose(stdout);
72 }
View Code

 

posted on 2018-08-19 18:56  cychester  阅读(147)  评论(2编辑  收藏  举报

导航