[SDOI2012]任務安排
阿新 • • 發佈:2020-09-16
解析
預算費用,和Luogu P2365 任務安排一樣
得到了同樣的式子
但是我們發現 \(sumt_i\) 可能小於零
也就是說我們需要的斜率可能不再具有單調性
所以我們要維護整個凸殼
那麼怎麼找到最佳的決策點呢?
其實就是 \(slope(m,m-1) < sumt_i\) 且 \(slope(m,m+1) >= sumt_i\) 中的 \(m\)
於是我們可以二分整個凸殼,找到這樣的點
也就是判斷等價於 \(slope(m , m + 1) >= sumt_i\)
滿足這個不等式的決策可能成為最有決策,記錄下來
然後我們要找凸殼中更靠前的,於是 \(r=mid-1\)
\(Code\)
#include<cstdio> using namespace std; typedef long long LL; const int N = 3e5 + 5; int n , q[N]; LL f[N] , T[N] , C[N] , s , t , c; double slope(int u , int v) { if (C[u] == C[v]) return 1.0 / 0.0; //當除數為零時,我們就返回個極大值,不寫這句只有80pts return 1.0 * ((f[u] - s * C[u]) - (f[v] - s * C[v])) / (1.0 * C[u] - C[v]); } int search(int l , int r , int m) { if (l == r) return q[l]; int mid , res = r; while (l <= r) { mid = (l + r) >> 1; if (slope(q[mid] , q[mid + 1]) >= m) res = mid , r = mid - 1; else l = mid + 1; } return q[res]; } int main() { scanf("%d%lld" , &n , &s); for(register int i = 1; i <= n; i++) scanf("%lld%lld" , &t , &c) , T[i] = T[i - 1] + t , C[i] = C[i - 1] + c; int r; q[r = 1] = 0; for(register int i = 1; i <= n; i++) { int j = search(1 , r , T[i]); f[i] = f[j] + T[i] * (C[i] - C[j]) + s * (C[n] - C[j]); while (r > 1 && slope(i , q[r]) < slope(q[r] , q[r - 1])) --r; q[++r] = i; } printf("%lld" , f[n]); }