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 }