51nod 1102 面积最大的矩形 && 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))

题面1:

?

题面2:

?

两道题除了数据范围不同,没有任何差异,两道题都可以o(n)(单调栈),o(nlog(n))(我自己的做法)解决。

解题思路1:(单调栈)

  1. 对于每个点找到右边第一个比它小的位置con1,并且找到左边第一个比它小的位置con2。
  2. 对于每个点更新答案为ans = max(ans, (con2-con1-1)*value[i])。
  3. 1的做法是两次裸的单调栈,时间复杂度为o(n)。

代码1:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//在新疆大学OJ提交需要将此处三个数组改为500010,否则会运行超时
ll a[50010];
int l[50010],r[50010];
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    ll ans = 0;
    for(int i = 1;i <= n; ++i){
        cin >> a[i];
    }
    a[0] = a[n+1] = -1;
    stack<int> s;
    s.push(1);
    for(int i = 2;i <= n+1; ++i){
        while(s.size() and a[i] < a[s.top()]){
            r[s.top()] = i;
            s.pop();
        }
        s.push(i);
    }
    while(s.size()) s.pop();
    s.push(n);
    for(int i = n-1;i >= 0; --i){
        while(s.size() and a[i] < a[s.top()]){
            l[s.top()] = i;
            s.pop();
        }
        s.push(i);
    }
    for(int i = 1;i <= n; ++i){
        ans = max(ans, (a[i]*(r[i]-l[i]-1)));
    }
    cout << ans << endl;
    return 0;
}

解题思路2:(拼凑段)

  1. 这是我自己瞎搞的写法,不知道算什么方法,不过大家可以看一看思路,可能什么时候就能用到了。
  2. 首先,记下输入的数字的位置,然后对这个结构体按数字从打到小排序。
  3. 遍历这个结构体数组(这时数字是从大到下的),段(一个结构体,有l,r,used三个成员变量,l指这个段的左端位置,r指这个段的右端位置)

    a. 若这个数字的原位置的左右边两个数字都已形成段,则将这两段拼成一段,具体做法是将左边段的r延长至右端,当前数字为这一段的最小值,更新ans。
    b. 若这个数字的原位置的左边形成段,右边没有形成段,则把这个数字加入到左边的段,当前数字为这一段的最小值,更新ans。
    c. 若这个数字的原位置的右边形成段,左边没有形成段,则把这个数字加入到右边的段,当前位置为这一段的最小值,更新ans。

    d. 若这个数字的原位置的左边和右边都没有形成段,则把这个数字加入到一个新的段,新的段的l和r都等于这个数字的原先位置,更新ans。

  4. 可能会想到查找左边位置所处的段和右边所处的段需要o(n)处理起来会变成o(n^2),这时候我们加一个索引数组index,index[i]表示位置为i的数字所处的段。
  5. 可能还会想到更新index需要花费o(n),处理起来会变成o(n^2),但是仔细想想我们会发现不需要更新这个段所有的index,只用更新index[l]和index[r],因为中间的在后面将不会用到。
  6. 这样算下来排序的时间复杂度是o(nlogn),处理的时间是o(n),总时间复杂度就是o(nlogn)。
  7. 可能还有人问为什么正确?排序之后先插入大的,后插入小的,会发现当前插入的这个点一定是这个点的最优情况。

代码2:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//在新疆大学OJ提交需要将此处的50010全部改为500010 

//输入的数组,val为这个点的数字,idx表示原下标。
struct node{
    ll val;
    int idx;
}a[50010];
//段,l表示左端,r表示右端 ,k表示段的个数。
struct segment{
    int l;int r;
}seg[50010];
int k = 1;
//index[i]表示第i个位置数字所处的段。
int index[50010];

int n;
bool cmp(node x,node y){
    return x.val > y.val;
}

int main(){
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    ll ans = 0;
    for(int i = 1;i <= n; ++i){
        cin >> a[i].val;
        a[i].idx = i;
        ans = max(ans , a[i].val);
    }
    sort(a+1, a+1+n, cmp);
    for(int i = 1;i <= n; ++i){
        int idxl = index[a[i].idx-1];
        int idxr = index[a[i].idx+1];
        if(idxl != 0 and idxr != 0){    //左右边都形成一段。
            seg[idxl].r = seg[idxr].r;
            index[seg[idxr].r] = idxl;
            ans = max(ans, a[i].val*(seg[idxl].r-seg[idxl].l+1));
        }else if(idxl != 0 and idxr == 0){  //左边形成段,右边未形成。
            seg[idxl].r++;
            index[a[i].idx] = idxl;
            ans = max(ans, a[i].val*(seg[idxl].r-seg[idxl].l+1));
        }else if(idxl == 0 and idxr != 0){  //右边形成段,左边未形成。
            seg[idxr].l--;
            index[a[i].idx] = idxr;
            ans = max(ans, a[i].val*(seg[idxr].r-seg[idxr].l+1));
        }else if(idxl == 0 and idxr == 0){  //左右边均未形成段。
            seg[k].l = a[i].idx;
            seg[k].r = a[i].idx;
            index[a[i].idx] = k;
            k++;
        }
    }
    cout << ans << endl;
    return 0;
}

51nod 1102 面积最大的矩形 && 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))

原文地址:https://www.cnblogs.com/zhangjiuding/p/9190198.html

时间: 2024-09-29 22:07:33

51nod 1102 面积最大的矩形 && 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))的相关文章

51Nod - 1102 面积最大的矩形

51Nod - 1102 面积最大的矩形 有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积.例如 2,1,5,6,2,3,对应的直方图如下: 面积最大的矩形为5,6组成的宽度为2的矩形,面积为10. Input 第1行:1个数N,表示数组的长度(0 <= N <= 50000) 第2 - N + 1行:数组元素A[i].(1 <= A[i] <= 10^9) Output 输出最大的矩形面积 Input示例 6 2 1 5 6 2 3 Output示例 10 题解: (

51nod 1102 面积最大的矩形(单调栈)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102 题意: 思路: 做法就是求出每个长方形向左向右所能延伸的最大距离. 我这里用单调栈来做,维护一个单调递增的栈(自底向上递增),如果当前值大于栈顶,那么直接进栈,如果小于的话,那就说明前面比它大的那些数最多只能延伸到它这里.自己手动模拟一下就可以了. 1 #include<iostream> 2 #include<algorithm> 3 #inclu

1102 面积最大的矩形

1102 面积最大的矩形 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积.例如 2,1,5,6,2,3,对应的直方图如下: 面积最大的矩形为5,6组成的宽度为2的矩形,面积为10. Input 第1行:1个数N,表示数组的长度(0 <= N <= 50000) 第2 - N + 1行:数组元素A[i].(1 <= A[i] <= 10^9) Output 输出最大的矩形面积 Input

51nod 1158 全是1的最大子矩阵(单调栈 ,o(n*m))

前置问题:51nod 1102 面积最大的矩形 附上链接: 51nod 1102 面积最大的矩形 这题的题解博客 需要了解的知识:单调栈,在前置问题中已经讲解. 解题思路 对每行求左边连续1的个数,得到数组a[i][j]; 对于第j列,找出每个位置i的数字a[i][j]上面第一个比它小数字l,和下面第一个比它小的数字r. 由这个点所在列为底,这个点的数字为最小值产生的矩形的面积为a[i][j]*(r-l-1),用这一列每一个面积更新ans. 上面2的求法就是单调栈了,总时间复杂度o(n*m).

寻找直方图中面积最大的矩形

Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectang

2015 百度之星 1006 矩形面积 最小点覆盖矩形

矩形面积 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acdream.info/problem?pid=1754 Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少. Input 第一行一个正整数 T,代表测试数据组数(1≤T≤20),接下来 T 组测试数据. 每组测试数据占若干行,第一行一个正整数 N(1≤N<≤1000),代表矩形的数量.接下来 N

百度之星 矩形面积(最小矩形覆盖)

矩形面积 Accepts: 717 Submissions: 1619 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少. Input 第一行一个正整数 T,代表测试数据组数(1≤T≤20),接下来 T 组测试数据. 每组测试数据占若干行

9715 相邻最大矩形面积 单调栈

9715 相邻最大矩形面积 时间限制:1000MS  内存限制:65535K提交次数:0 通过次数:0 题型: 编程题   语言: G++;GCC;VC;JAVA Description 在X轴上水平放置着 N 个条形图,这 N 个条形图就组成了一个柱状图,每个条形图都是一个矩形,每个 矩形都有相同的宽度,均为1单位长度,但是它们的高度并不相同. 例如下图,图1包含的矩形的高分别为2,1,4,5,1,3,3 单位长度,矩形的宽为1单位长度. 你的任务就是计算柱状图中以X轴为底边的最大矩形的面积.

这样画面积一定的矩形,简单易懂!

矩形是基本的几何图形,在学习该图形时,会研究面积一定的矩形,它们到底有哪些形状的?其实为了能展示各种形状的矩形,可以借助专业的几何绘图软件来制作动画进行演示,下面就一起来学习具体制作技巧. 几何画板作为专业的几何绘图工具,这里就借助该工具来制作,大家可以访问http://wm.makeding.com/iclk/?zoneid=17783去下载软件. 演示面积一定的矩形课件样图:  几何画板课件模板--演示面积一定的矩形 以上课件中,演示的是面积一定的矩形,不管矩形的长和宽如何变化,矩形的面积都