题目链接:点击查看

题目大意:给出一个长度为 nnn 的序列,求出所有子区间的最大值与最小值之差的和

题目分析:不难看出最大值和最小值之差的和可以拆开,拆成最大值之和最小值之和之差,现在问题转换为如何求解所有子区间内的最值之和

可以单调栈维护每个数字的可行范围,这里以最小值为例,当我们遍历到 iii 位置时,我们只需要求出左侧首次小于 a[i]a[i]a[i] 的位置 lll,以及右侧首次小于 a[i]a[i]a[i] 的位置 rrr,那么 a[i]a[i]a[i] 的贡献就是:左端点属于区间 [l,i][l,i][l,i],同时右端点属于区间 [i,r][i,r][i,r] 的子区间了。

但是上述做法只适用于 nnn 个数字互不相同,如果遇到重复的数字会重复计算答案。

该怎么解决呢?其实仔细思考一下不难发现,可以令区间变成左闭右开或左开右闭,换句话说我们只需要让 lll 变成左侧首个小于等于 a[i]a[i]a[i] 的位置或者让 rrr 变成右侧首个小于等于 a[i]a[i]a[i] 的位置就好了

具体证明可以口胡一下,对于一段连续数列 {2,2,2}\{2,2,2\}{2,2,2} 来说,如果 lll 表示的是左侧首个小于 a[i]a[i]a[i] 的位置,rrr 表示的是右侧首个小于等于 a[i]a[i]a[i] 的位置,那么得到的三个开区间就是 (0,2),(0,3),(0,4)(0,2),(0,3),(0,4)(0,2),(0,3),(0,4),发现确实是覆盖了所有的区间

代码:

// Problem: J - Imbalanced Array
// Contest: Virtual Judge - 7.31限时训练(生成树,树的直径,单调栈)2
// URL: https://vjudge.net/contest/450440#problem/J
// Memory Limit: 262 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int l[N],r[N];
LL a[N];
stack<int>st;
void init() {while(st.size()) {st.pop();}
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n;LL ans=0;read(n);for(int i=1;i<=n;i++) {read(a[i]);}init();for(int i=1;i<=n;i++) {while(st.size()&&a[st.top()]<=a[i]) st.pop();if(st.empty()) l[i]=0;else l[i]=st.top();st.push(i);}init();for(int i=n;i>=1;i--) {while(st.size()&&a[st.top()]<a[i]) st.pop();if(st.empty()) r[i]=n+1;else r[i]=st.top();st.push(i);}for(int i=1;i<=n;i++) {ans+=a[i]*(r[i]-i)*(i-l[i]);}init();for(int i=1;i<=n;i++) {while(st.size()&&a[st.top()]>=a[i]) st.pop();if(st.empty()) l[i]=0;else l[i]=st.top();st.push(i);}init();for(int i=n;i>=1;i--) {while(st.size()&&a[st.top()]>a[i]) st.pop();if(st.empty()) r[i]=n+1;else r[i]=st.top();st.push(i);}for(int i=1;i<=n;i++) {ans-=a[i]*(r[i]-i)*(i-l[i]);}cout<<ans<<endl;return 0;
}

CodeForces - 817D Imbalanced Array(单调栈)相关推荐

  1. [cf] Codeforces 817D Imbalanced Array 单调栈

    前言 传送门 : 优质题解传送门 : wls题目传送门 : 思路 使用单调栈维护当前节点 是最大值的时候的区间 以及当前节点是最小值时候的区间 然后统计计数即可 而求区间最大最小值可以使用单调栈处理 ...

  2. CF817D Imbalanced Array(单调栈+区间交集的处理)

    原题链接 题意: 对于给定由 n 个元素构成的数组.一个子数组的不平衡值是这个区间的最大值与最小值的差值.数组的不平衡值是它所有子数组的不平衡值的总和.求数组的不平衡值. 思路: 跟上题类似,由于子区 ...

  3. Codeforces 1300E. Water Balance[单调栈]

    题目链接 题目大意:给你一个长度为n的数组,你可以选择一段区间将这段区间的数全都变成这段区间的平均值,问你最后这个数组字典序最小是怎么样的 解题思路:1.首先我们知道最后这个序列一定会变成一个单调上升 ...

  4. CodeForces - 91 B.Queue (单调栈)

    题意: 给长度为n的数列,找到每个数右边距离他最远的比他小数,输出他们之间有多少个数,如果右边没有比他小的,输出-1. 分析: 因为要找从右边开始第一个比他小的数 因此从右边向左遍历,同时维护一个递减 ...

  5. CF817D Imbalanced Array(单调栈)

    CF817D Imbalanced Array 题目传送门 解题思路 根据一位巨佬的题解 枚举当前点在什么区间内是最小值和最大值 可以用四个单调栈 一个找当前点为区间最小值时,区间的最左端(minl) ...

  6. CodeForces - 1484E Skyline Photo(dp+单调栈)

    题目链接:点击查看 题目大意:给出 nnn 个建筑,每个建筑有一个高度和一个美丽值,现在要求划分为数个连续的区间,使得所有区间的贡献之和最大,其中每个区间的贡献值为,区间中高度最低的建筑物的美丽值 题 ...

  7. CodeForces - 1506G Maximize the Remaining String(单调栈+贪心)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,假设共出现了 kkk 种字母,现在要求出一个长度为 kkk 的子序列,满足每种字母只出现一次,且字典序最大 题目分析:和之前牛客上的一道 ...

  8. 【CodeForces - 602D】Lipshitz Sequence(思维,单调栈,斜率单调性)

    题干: A function  is called Lipschitz continuous if there is a real constant Ksuch that the inequality ...

  9. 【Codeforces 549F】Yura and Developers | 单调栈、启发式合并、二分

    题目链接:https://codeforces.com/problemset/problem/549/F 题目大意: 给定一个序列和一个mod值,定义[l,r]合法当l到r的所有元素和减去其中的最大值 ...

最新文章

  1. linux5启动过程及故障排除
  2. 定制适合自己的精简桌面环境
  3. 基于JAVA+Servlet+JSP+MYSQL的高校后勤管理系统
  4. UVa 10570 - Meeting with Aliens
  5. 个推透传工作笔记001---个推后台配置
  6. 计算机二级修改并应用基本简历模板,2020年新版个人简历模板大全可编辑(word版).docx...
  7. 在线购物系统-面对对象设计
  8. 欧拉环游和中国邮递员问题
  9. ATX电源工作原理的学习
  10. 信而泰 X-Snapper测试系统,助力家庭路由器IPv6支持度测试
  11. FLUX-TMS-物流整体解决方案 附下载地址
  12. 辉光管时钟系列<三>时钟芯片DS12C887
  13. 华为2020校招-数字化IT应用工程师-凉经
  14. 自制裸眼3D图【推荐】
  15. 同一个按钮点击多次不同效果_如何解决竞价推广中的恶意点击?
  16. nodeJS实现简单网页爬虫功能
  17. Xposed 模块开发入门
  18. C++数字三角形问题(动态规划)
  19. 架构师,你需要了解的git知识都在这里了
  20. 迅雷2014C++研发笔试卷C解题分析

热门文章

  1. linux java top_Linux top和负载的解释(转载)
  2. 酒店管理系统c语言带注释,酒店管理系统--C语言版.pdf
  3. mysql登陆salt_salt把返回写入到mysql
  4. Nginx反向代理的实战案例
  5. Nginx全局块的工作进程的两个指令
  6. 基于Xml 的IOC 容器的初始化
  7. 反射_获取字节码Class对象的三种方式
  8. 字节输入流_InputStream类FileInputStream类介绍
  9. 数据库-第三范式及BCN
  10. ServletContext_功能_获取MIME类型