51nod 1215 单调栈/迭代

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1215

1215 数组的宽度

题目来源: Javaman

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

收藏

关注

N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和。

Input

第1行:1个数N,表示数组的长度。(1 <= N <= 50000)
第2 - N + 1行:每行1个数,表示数组中的元素(1 <= A[i] <= 50000)

Output

输出所有子数组的宽度和。

Input示例

5
1
2
3
4
5

Output示例

20感觉很经典的题目。   首先我们不可能枚举出所有的子区间,显然时空是不允许的,那就要从元素入手,我们只要知道每个元素被作为最大最小值得次数答案就出来了,问题转化为求元素作为最值的次数。可以找到当前元素作为最大/小值时对应的最大的区间左右端点,然后组合计算一下就是答案了。找这个左右端点时可以用单调栈也可以迭代搜索,stl貌似要慢一些。   正确性在于找端点时满足决策单调性,例如找最大值左端点时,这个元素左侧的元素如果大于他,那显然左端点就是他本身了,此时就是一个单调递减栈,大于栈顶元素时左端点就可以用栈顶元素的左端点代替;  总之就一句话,大于左侧的元素,一定大于所有左侧元素能大于的元素。   还有就是第一次WA了因为重复计算了, 只要稍微修改一下为左侧不严格右侧严格的查找就好了。
 1 #include <iostream>
 2 #include<algorithm>
 3 #include<stack>
 4 #include<cstdio>
 5 using namespace std;
 6 typedef long long LL;
 7 const int MAX = 50005;
 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
 9 int maxt[MAX], mint[MAX];
10 stack<int>S;
11 int main()
12 {
13     int N, i, j, k;
14     scanf("%d", &N);
15     for (i = 1;i <= N;++i) scanf("%d", a + i);
16     for (i = 1;i <= N;++i)
17     {
18         if (S.empty() || a[i] < a[S.top()]) {
19             l1[i] = i;
20             S.push(i);
21         }
22         else {
23             while (!S.empty() && a[S.top()] <= a[i]) {
24                 l1[i] = l1[S.top()];
25                 S.pop();
26             }
27             S.push(i);
28         }
29     }while (!S.empty()) S.pop();
30     for (i = N;i >=1;--i)
31     {
32         if (S.empty() || a[i] <= a[S.top()]) {
33             r1[i] = i;
34             S.push(i);
35         }
36         else {
37             while (!S.empty() && a[S.top()] < a[i]) {
38                 r1[i] = r1[S.top()];
39                 S.pop();
40             }
41             S.push(i);
42         }
43     }while (!S.empty()) S.pop();
44     for (i = 1;i <= N;++i)
45     {
46         maxt[i] += (r1[i]-l1[i])+(i-l1[i])*(r1[i]-i);
47     }
48     for (i = 1;i <= N;++i)
49     {
50         if (S.empty() || a[i] > a[S.top()]) {
51             l2[i] = i;
52             S.push(i);
53         }
54         else {
55             while (!S.empty() && a[S.top()] >=a[i]) {
56                 l2[i] = l2[S.top()];
57                 S.pop();
58             }
59             S.push(i);
60         }
61     }while (!S.empty()) S.pop();
62     for (i = N;i>=1;--i)
63     {
64         if (S.empty() || a[i] >= a[S.top()]) {
65             r2[i] = i;
66             S.push(i);
67         }
68         else {
69             while (!S.empty() && a[S.top()] > a[i]) {
70                 r2[i] = r2[S.top()];
71                 S.pop();
72             }
73             S.push(i);
74         }
75     }while (!S.empty()) S.pop();
76     for (i = 1;i <= N;++i)
77     {
78         mint[i] += (-l2[i]+r2[i])+(i-l2[i])*(r2[i]-i);
79     }
80     LL ans = 0;
81     for (i = 1;i <= N;++i)
82     {
83         ans += (LL)a[i] * (maxt[i]-mint[i]);
84     }
85     printf("%lld\n", ans);
86     return 0;
87 }

迭代:

 1 #include <iostream>
 2 #include<algorithm>
 3 #include<stack>
 4 #include<cstdio>
 5 using namespace std;
 6 typedef long long LL;
 7 const int MAX = 50005;
 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
 9 int maxt[MAX], mint[MAX];
10 int main()
11 {
12     int N, i, j, k;
13     scanf("%d", &N);
14     for (i = 1;i <= N;++i) scanf("%d", a + i);
15     for (i = 1;i <= N;++i) {
16         l1[i] = r1[i] = i;
17         l2[i] = r2[i] = i;
18     }
19     for (i = 1;i <= N;++i) {
20         while (l1[i] != 1 && a[i] >= a[l1[i] - 1])
21             l1[i] = l1[l1[i]-1];
22         while (l2[i] != 1 && a[i] <= a[l2[i] - 1])
23             l2[i] = l2[l2[i] - 1];
24     }
25     for (i = N;i >= 1;--i) {
26         while (r1[i] != N&&a[i] > a[r1[i] + 1])
27             r1[i] = r1[r1[i] + 1];
28         while (r2[i] != N&&a[i] < a[r2[i] + 1])
29             r2[i] = r2[r2[i] + 1];
30     }
31     LL ans = 0;
32     for (i = 1;i <= N;++i) {
33         ans += (LL)a[i] * ((r1[i] - l1[i]) + (i - l1[i])*(r1[i] - i)- (-l2[i] + r2[i]) - (i - l2[i])*(r2[i] - i));
34     }
35     cout << ans << endl;
36     //system("pause");
37     return 0;
38 }
时间: 2024-11-03 02:53:18

51nod 1215 单调栈/迭代的相关文章

51nod 1279 单调栈

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1279 1279 扔盘子 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注 有一口井,井的高度为N,每隔1个单位它的宽度有变化.现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去). 盘子有几种命运:1.掉到井底.2.被卡住.3.落到别的盘子上方. 盘子

51nod 1215 数组的宽度&amp;poj 2796 Feel Good(单调栈)

单调栈求每个数在哪些区间是最值的经典操作. 把数一个一个丢进单调栈,弹出的时候[st[top-1]+1,i-1]这段区间就是弹出的数为最值的区间. poj2796 弹出的时候更新答案即可 #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<cmath

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

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

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).

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

题面1: ? 题面2: ? 两道题除了数据范围不同,没有任何差异,两道题都可以o(n)(单调栈),o(nlog(n))(我自己的做法)解决. 解题思路1:(单调栈) 对于每个点找到右边第一个比它小的位置con1,并且找到左边第一个比它小的位置con2. 对于每个点更新答案为ans = max(ans, (con2-con1-1)*value[i]). 1的做法是两次裸的单调栈,时间复杂度为o(n). 代码1: #include <bits/stdc++.h> using namespace s

HDU -1506 Largest Rectangle in a Histogram&amp;&amp;51nod 1158 全是1的最大子矩阵 (单调栈)

单调栈和队列讲解:传送门 HDU -1506题意: 就是给你一些矩形的高度,让你统计由这些矩形构成的那个矩形面积最大 如上图所示,如果题目给出的全部是递增的,那么就可以用贪心来解决 从左向右依次让每一个矩形的高度当作最后的高度,来从中选取最大值就可以了 但是如果它不是递增的,中间会出现低谷,那么要还想运用贪心策略就要把之前高度大于它的全部扔掉,但是再扔掉他们之前还要判断一下以他们为最后答案的高度可不可行,这样我们就是在构造一个递增序列,可以用栈来维护它 代码: 1 #include<stdio.

[51nod 1288]汽油补给(ST表+单调栈)

[51nod 1288]汽油补给(ST表+单调栈) 题面 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T.给出每个城市到下一个城市的距离D,以及当地的油价P,求走完整个旅途最少的花费.如果无法从起点到达终点输出-1. 分析 贪心考虑,当我们到达一个城市x的时候,我们下一个到的城市应该是在x加满油的情况下,能到达的油价比x低的城市.如果每个加油城市之间的路都这样走,那么最后的价钱一定是最小的.

51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

 区间计数 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{Ai,Ai+1,...,Aj}=max{Bi,Bi+1,...,Bj}] 注:[ ]内表达式为真,则为1,否则为0. 1≤N≤3.5×1051≤Ai,Bi≤N 样例解释: 7个区间分别为:(1,4),(1,5),(2,4),(2,5),(3,3),(3,5),(4,5) Input 第一行一个整数N 第二行

51nod1102(单调栈/预处理)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102 题意:中文题诶- 思路:单调栈/预处理 (这篇博客就不细写了啦,只给出代码和转过来的两篇不错的题解,好困了-) 单调栈:http://blog.csdn.net/u012773338/article/details/40265223 代码: #include <iostream> #include <stack> #define ll l