[USACO2012 OPEN] Bookshelf
阿新 • • 發佈:2018-11-07
[題目連結]
https://www.lydsy.com/JudgeOnline/problem.php?id=2678
[演算法]
首先不難想到如下DP :
記f[i]表示前i本書的高度和最小值
顯然 , 有狀態轉移方程 : f[i] = min{ fj + max{hj+1 , hj+2 , ... hi} }
不難發現 , 當i確定時 , 隨著j的減小 , max{hj + 1 , hj+2 , ... hi}的值單調遞增
不妨維護一個單調遞減的單調棧
預處理字首和 , 每次在單調棧中二分出最靠左的左端點
然後 , 我們還需維護一棵支援單點修改 , 區間查詢的線段樹
每次線上段樹中找到從合法左端點到當前點的最小值
詳見程式碼 , 時間複雜度 : O(NlogN)
#include<bits/stdc++.h> using namespace std; #define MAXN 100010 typedef long long LL; const LL inf = 1e18; struct info { LL h , w; } a[MAXN]; LL n , top; LL L; int s[MAXN]; LL cnt[MAXN] , dp[MAXN]; struct Segment_Tree { struct Node { int l , r; LL mn; } Tree[MAXN<< 2]; inline void build(int index , int l , int r) { Tree[index] = (Node){l , r , inf}; if (l == r) return; int mid = (l + r) >> 1; build(index << 1 , l , mid); build(index << 1 | 1 , mid + 1 , r); } inline void update(int index) { Tree[index].mn = min(Tree[index << 1].mn , Tree[index << 1 | 1].mn); } inline void modify(int index , int pos , LL value) { if (Tree[index].l == Tree[index].r) { Tree[index].mn = value; return; } int mid = (Tree[index].l + Tree[index].r) >> 1; if (mid >= pos) modify(index << 1 , pos , value); else modify(index << 1 | 1 , pos , value); update(index); } inline LL query(int index , int l , int r) { if (l > r) return inf; if (Tree[index].l == l && Tree[index].r == r) return Tree[index].mn; int mid = (Tree[index].l + Tree[index].r) >> 1; if (mid >= r) return query(index << 1 , l , r); else if (mid + 1 <= l) return query(index << 1 | 1 , l , r); else return min(query(index << 1 , l , mid) , query(index << 1 | 1 , mid + 1 , r)); } } SGT; template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } int main() { read(n); read(L); for (int i = 1; i <= n; i++) { read(a[i].h); read(a[i].w); cnt[i] = cnt[i - 1] + a[i].w; } SGT.build(1 , 1 , n + 1); s[top = 1] = 0; dp[0] = s[0] = 0; SGT.modify(1 , 1 , 0); for (int i = 1; i <= n; i++) { while (top > 0 && a[i].h > a[s[top]].h) --top; s[++top] = i; SGT.modify(1 , top , dp[s[top - 1]] + a[i].h); int l = 1 , r = top , pos = 0; while (l <= r) { int mid = (l + r) >> 1; if (cnt[i] - cnt[s[mid]] <= L) { pos = mid; r = mid - 1; } else l = mid + 1; } int loc = lower_bound(cnt , cnt + n + 1 , cnt[i] - L) - cnt; dp[i] = SGT.query(1 , pos + 1 , top); chkmin(dp[i] , dp[loc] + a[s[pos]].h); } cout<< dp[n] << '\n'; return 0; }