1. 程式人生 > >[USACO2012 OPEN] Bookshelf

[USACO2012 OPEN] Bookshelf

[題目連結]

         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; }