• ACM学习历程—广东工业大学2016校赛决赛-网络赛E 积木积水(最值问题 || 动态规划)


    题目链接:http://gdutcode.sinaapp.com/problem.php?cid=1031&pid=4

    这个题目自然会考虑到去讨论最长或者最短的板子。

    笔上大概模拟一下的话,就会知道,假设最长的板子是r0n+1位置上都是高度为0的板子,那么对于[0, r-1]中的最长板子rrrrr这一短应该都是被深度为a[rr]的水覆盖。同样的[0, rr-1]中的最长板子rrrrrrrr这一段应该是被a[rrr]覆盖,以此类推可以搞定r的前面一段,同理搞定后一段。

    关于最值这一块,可以使用RMQ之类的logn维护,总的复杂度是nlogn。但是考虑到区间都是[0, r][r, n+1]这种的。所以很容易想到DPp[0][i]表示从0到i区间内最大值的角标,p[1][i]表示从i到n+1区间内最大值的角标。然后两遍方程转移。总的复杂度是O(n)。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <vector>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    const int maxN = 1e6+5;
    int n, a[maxN];
    
    //RMQ-ST算法
    //效率nlogn
    //查询区间最值,注意区间[0, n-1]和[1, n]的区别
    int ma[maxN][20];
    
    void RMQ()
    {
        memset(ma, 0, sizeof(ma));
        for (int i = 0; i <= n+1; ++i)
            ma[i][0] = i;
        for (int j = 1; (1<<j) <= n+2; ++j)
            for (int i = 0; i+(1<<j)-1 <= n+1; ++i)
            {
                if (a[ma[i][j-1]] > a[ma[i+(1<<(j-1))][j-1]])
                    ma[i][j] = ma[i][j-1];
                else
                    ma[i][j] = ma[i+(1<<(j-1))][j-1];
            }
    }
    
    int query(int lt, int rt)
    {
        int k = 0;
        while ((1<<(k+1)) <= rt-lt+1)
            k++;
        if (a[ma[lt][k]] > a[ma[rt-(1<<k)+1][k]])
            return ma[lt][k];
        else
            return ma[rt-(1<<k)+1][k];
    }
    
    
    void input()
    {
        scanf("%d", &n);
        a[0] = a[n+1] = 0;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        RMQ();
    }
    
    LL cal(int lt, int rt, int h)
    {
        LL ans = 0;
        for (int i = lt; i <= rt; ++i)
            ans += max(0, h-a[i]);
        return ans;
    }
    
    void work()
    {
        LL ans = 0;
        int mid = query(0, n+1), k, now;
        now = mid;
        while (now > 0)
        {
            k = query(0, now-1);
            ans += cal(k, now-1, a[k]);
            now = k;
        }
        now = mid;
        while (now < n+1)
        {
            k = query(now+1, n+1);
            ans += cal(now+1, k, a[k]);
            now = k;
        }
        cout << ans << endl;
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            input();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    ECSHOP获取当前分类所在顶级分类信息
    二级域名会不会分散主域名权重
    ECSHOP增加模板页的方法
    ECSHOP之transport.js/run() error:'process_request' 未定义
    AIR任务栏图标的闪烁
    googlemap数据采集器(三)
    Flex中List自己定义itemrenderer渲染问题的解决
    GIS理论(墨卡托投影、地理坐标系、地面分辨率、地图比例尺、Bing Maps Tile System)
    android下歌曲名称乱码的解决办法
    史上最强劲的android模拟器命令详解
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5375240.html
Copyright © 2020-2023  润新知