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

        

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9925900.html