• [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] << '
    ';
        
        return 0;
    }

            

  • 相关阅读:
    51 Nod 1068 Bash游戏v3
    51 Nod Bash 游戏v2
    51 Nod 1073 约瑟夫环
    UVA 12063 Zeros and ones 一道需要好好体会的好题
    51 Nod 1161 Partial sums
    2018中国大学生程序设计竞赛
    UVA 11971 Polygon
    UVA 10900 So do you want to be a 2^n-aire?
    UVA 11346 Possibility
    python with as 的用法
  • 原文地址:https://www.cnblogs.com/evenbao/p/9925900.html
Copyright © 2020-2023  润新知