51nod 1215 单调栈/迭代
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1215
第1行:1个数N,表示数组的长度。(1 <= N <= 50000)
第2 - N + 1行:每行1个数,表示数组中的元素(1 <= A[i] <= 50000)
输出所有子数组的宽度和。
5
1
2
3
4
5
20
感觉很经典的题目。
首先我们不可能枚举出所有的子区间,显然时空是不允许的,那就要从元素入手,我们只要知道每个元素被作为最大最小值得次数答案就出来了,问题转化为求元素作为最值的次数。
可以找到当前元素作为最大/小值时对应的最大的区间左右端点,然后组合计算一下就是答案了。找这个左右端点时可以用单调栈也可以迭代搜索,stl貌似要慢一些。
正确性在于找端点时满足决策单调性,例如找最大值左端点时,这个元素左侧的元素如果大于他,那显然左端点就是他本身了,此时就是一个单调递减栈,大于栈顶元素时左端点就可以用栈顶
元素的左端点代替;
总之就一句话,大于左侧的元素,一定大于所有左侧元素能大于的元素。
还有就是第一次WA了因为重复计算了, 只要稍微修改一下为左侧不严格右侧严格的查找就好了。
#include <iostream>
#include<algorithm>
#include<stack>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAX = ;
int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
int maxt[MAX], mint[MAX];
stack<int>S;
int main()
{
int N, i, j, k;
scanf("%d", &N);
for (i = ;i <= N;++i) scanf("%d", a + i);
for (i = ;i <= N;++i)
{
if (S.empty() || a[i] < a[S.top()]) {
l1[i] = i;
S.push(i);
}
else {
while (!S.empty() && a[S.top()] <= a[i]) {
l1[i] = l1[S.top()];
S.pop();
}
S.push(i);
}
}while (!S.empty()) S.pop();
for (i = N;i >=;--i)
{
if (S.empty() || a[i] <= a[S.top()]) {
r1[i] = i;
S.push(i);
}
else {
while (!S.empty() && a[S.top()] < a[i]) {
r1[i] = r1[S.top()];
S.pop();
}
S.push(i);
}
}while (!S.empty()) S.pop();
for (i = ;i <= N;++i)
{
maxt[i] += (r1[i]-l1[i])+(i-l1[i])*(r1[i]-i);
}
for (i = ;i <= N;++i)
{
if (S.empty() || a[i] > a[S.top()]) {
l2[i] = i;
S.push(i);
}
else {
while (!S.empty() && a[S.top()] >=a[i]) {
l2[i] = l2[S.top()];
S.pop();
}
S.push(i);
}
}while (!S.empty()) S.pop();
for (i = N;i>=;--i)
{
if (S.empty() || a[i] >= a[S.top()]) {
r2[i] = i;
S.push(i);
}
else {
while (!S.empty() && a[S.top()] > a[i]) {
r2[i] = r2[S.top()];
S.pop();
}
S.push(i);
}
}while (!S.empty()) S.pop();
for (i = ;i <= N;++i)
{
mint[i] += (-l2[i]+r2[i])+(i-l2[i])*(r2[i]-i);
}
LL ans = ;
for (i = ;i <= N;++i)
{
ans += (LL)a[i] * (maxt[i]-mint[i]);
}
printf("%lld\n", ans);
return ;
}
迭代:
#include <iostream>
#include<algorithm>
#include<stack>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAX = ;
int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
int maxt[MAX], mint[MAX];
int main()
{
int N, i, j, k;
scanf("%d", &N);
for (i = ;i <= N;++i) scanf("%d", a + i);
for (i = ;i <= N;++i) {
l1[i] = r1[i] = i;
l2[i] = r2[i] = i;
}
for (i = ;i <= N;++i) {
while (l1[i] != && a[i] >= a[l1[i] - ])
l1[i] = l1[l1[i]-];
while (l2[i] != && a[i] <= a[l2[i] - ])
l2[i] = l2[l2[i] - ];
}
for (i = N;i >= ;--i) {
while (r1[i] != N&&a[i] > a[r1[i] + ])
r1[i] = r1[r1[i] + ];
while (r2[i] != N&&a[i] < a[r2[i] + ])
r2[i] = r2[r2[i] + ];
}
LL ans = ;
for (i = ;i <= N;++i) {
ans += (LL)a[i] * ((r1[i] - l1[i]) + (i - l1[i])*(r1[i] - i)- (-l2[i] + r2[i]) - (i - l2[i])*(r2[i] - i));
}
cout << ans << endl;
//system("pause");
return ;
}
51nod 1215 单调栈/迭代的更多相关文章
- 51nod 1102 单调栈
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102 1102 面积最大的矩形 基准时间限制:1 秒 空间限制:1310 ...
- 51nod 1279 单调栈
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1279 1279 扔盘子 题目来源: Codility 基准时间限制:1 ...
- 51nod 1215 数组的宽度&poj 2796 Feel Good(单调栈)
单调栈求每个数在哪些区间是最值的经典操作. 把数一个一个丢进单调栈,弹出的时候[st[top-1]+1,i-1]这段区间就是弹出的数为最值的区间. poj2796 弹出的时候更新答案即可 #inclu ...
- 51nod 1437 迈克步(单调栈)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1437 题意: 思路: 单调栈题.求出以每个数为区间最大值的区间范围即可. ...
- 51nod 1102 面积最大的矩形 (单调栈)
链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102 思路: 首先介绍下单调栈的功能:利用单调栈,可以找到从左/ ...
- 51nod 1102 面积最大的矩形(单调栈)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102 题意: 思路: 做法就是求出每个长方形向左向右所能延伸的最大距离. ...
- 51Nod 1158 全是1的最大子矩阵 —— 预处理 + 暴力枚举 or 单调栈
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1158 1158 全是1的最大子矩阵 基准时间限制:1 秒 空 ...
- 51nod 1158 全是1的最大子矩阵(单调栈 ,o(n*m))
前置问题:51nod 1102 面积最大的矩形 附上链接: 51nod 1102 面积最大的矩形 这题的题解博客 需要了解的知识:单调栈,在前置问题中已经讲解. 解题思路 对每行求左边连续1的个数,得 ...
- [多校联考2019(Round 4 T2)][51nod 1288]汽油补给(ST表+单调栈)
[51nod 1288]汽油补给(ST表+单调栈) 题面 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的 ...
随机推荐
- 流畅的python python 序列
内置序列 容器类型 list .tuple和collections.deque这些序列能放入不同的类型的数据 扁平序列 str.byets.bytearray.memoryview(内存视图)和arr ...
- 约束、自定义异常、hashlib模块、logging日志模块
一.约束(重要***) 1.首先我们来说一下java和c#中的一些知识,学过java的人应该知道,java中除了有类和对象之外,还有接口类型,java规定,接口中不允许在方法内部写代码,只能约束继承它 ...
- 设计线程安全的类 VS 发布线程安全的对象
一.设计线程安全的类 步骤: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 1.在现有的线程安全类中添加功能 (1)重用能减低工作量和提高正确性 (2)如果底层 ...
- (4.9)SQL Server如何校验备份文件
译 SQL Server如何校验备份文件 转自:https://blog.csdn.net/tjvictor/article/details/5261666 RESTORE VERIFYONLY与 c ...
- Mybatis中insert返回主键ID
记录解决的过程,这里就不搬砖了. 1.获取insert后的主键id 原文链接:http://www.cnblogs.com/fsjohnhuang/p/4078659.html 2.insert后返回 ...
- STL之空间配置器
在前面很多随笔里都有提到new对象是先分配内存然后初始化对象,主要是对operator new和placement new的使用 在SGI STL中内存的分配和初始化是分开的,分配内存是使用类模板,模 ...
- 剑指offer 面试40题
面试40题: 题目:最小的k个数 题:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 解题代码一: # -*- coding ...
- 神奇的Timer
最近的一个项目有一些地方需要用到定时功能,在设计过程中,突然发现.net的Timer类居然还有很多我以前没有用过的功能,这里就跟大家分享一下 注:这里的Timer类特指System.Threading ...
- Linux基础系列:常用命令(1)
1.开启Linux操作系统,要求以root用户登录GNOME图形界面,语言支持选择为汉语 2.使用快捷键切换到虚拟终端2,使用普通用户身份登录,查看系统提示符 命令:ctrl+alt+F2 3.使用命 ...
- oracle数据向历史表数据迁移————procedure
create or replace procedure remove_refund_his_pro isbegin declare cursor refund_query_cur is select ...