NC20806 区区区间间间
NC20806 区区区间间间
题目
题目描述
给出长度为n的序列a,其中第i个元素为 \(a_i\),定义区间(l,r)的价值为
\(v_{l,r} = max(a_i - a_j | l \leqslant i,j\leqslant r)\)
请你计算出 \(\sum_{l = 1}^n \sum_{r = l + 1}^n v_{l,r}\)
输入描述
第一行输入数据组数T
对于每组数据,第一行为一个整数n,表示序列长度
接下来一行有n个数,表示序列内的元素
输出描述
对于每组数据,输出一个整数表示答案
示例1
输入
3
3
4 2 3
5
1 8 4 3 9
20
2 8 15 1 10 5 19 19 3 5 6 6 2 8 2 12 16 3 8 17
输出
5
57
2712
说明
对于一组测试数据的解释:
区间[1, 2]的贡献为:4 - 2 = 2
区间[1, 3]的贡献为:4 - 2 = 2
区间[2, 3]的贡献为:3 - 2 = 1
2 + 1 + 2 = 5.
备注:
\(T \leqslant 20,n\leqslant 10^5, 0 \leqslant a_i \leqslant 10^5\)
不保证数据随机生成!
题解
思路
知识点:单调栈。
\(\sum_{l = 1}^n \sum_{r = l + 1}^n v_{l,r} = \sum_{l = 1}^n \sum_{r = l + 1}^n (max_{l,r} - min_{l,r})\) ,即所有子区间最大值之和减去所有子区间最小值之和。枚举端点用单调队列维护最小最大值,复杂度是 \(O(n^2)\)。换一个角度考虑,把每个元素当作最大/最小值,看看能维持左右多长,再将端点数相乘即可,这里用单调栈维护最邻近大于/小于。
细节上注意,以最大值为例,如果两个相同的元素,!s1.empty() && a[s1.top()] <= a[i]
都用小于等于作为弹出条件,那么这两个元素的扩展区间是完全相同的,从而左侧元素的右侧扩展和右侧元素的左侧扩展会有重复,因此保留一侧扩展而另一侧到小于等于就停,即 !s2.empty() && a[s2.top()] < a[i]
。
并且长度为 \(1\) 的区间不能算入其中,因此区间总数是 \((r[i] - i + 1) * (i - l[i] + 1) - 1\) ,但是由于长度为一的区间在最大值减去最小值过程会被消去,因此不减一也行。
这里有个小技巧,找最邻近大于时,即最小值扩展距离,可以将原数组取相反数,此时最小的会变成最大的,可以用最大值的方式求取,最后答案取相反数即可。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n;
int a[100007], l[100007], r[100007];
ll calc() {
stack<int> s1, s2;
for (int i = 0;i < n;i++) {
while (!s1.empty() && a[s1.top()] <= a[i]) s1.pop();
l[i] = s1.empty() ? 0 : s1.top() + 1;
s1.push(i);
}
for (int i = n - 1;i >= 0;i--) {
while (!s2.empty() && a[s2.top()] < a[i]) s2.pop();///防止相等元素重复计算
r[i] = s2.empty() ? n - 1 : s2.top() - 1;
s2.push(i);
}
ll sum = 0;
for (int i = 0;i < n;i++)
sum += (1LL * (r[i] - i + 1) * (i - l[i] + 1) - 1) * a[i];
return sum;
}
bool solve() {
cin >> n;
for (int i = 0;i < n;i++) cin >> a[i];
ll mx = calc();
for (int i = 0;i < n;i++) a[i] = -a[i];///取相反数,最小值变最大值可以用同一种操作
ll mn = -calc();
cout << mx - mn << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
NC20806 区区区间间间的更多相关文章
- 牛客网 223C 区区区间间间(单调栈)
题目链接:区区区间间间 题意:给出长度为n的数字序列ai,定义区间(l,r)的价值为, 请你计算出. 题解:单调栈求ai左边和右边第一个比它小的位置,需要减去ai的个数为$(R_i-i+1)*(i-L ...
- NowCoder--牛可乐发红包脱单ACM赛C_区区区间间间
题目链接:C_区区区间间间 思路:算贡献,求出每个数为当前最大值时所在的区间个数,和每个数为最小值的区间个数 和这个题有点类似 搭配食用效果更佳 点击这里 #include<bits/stdc+ ...
- 牛客ACM赛 C 区区区间间间
链接 C 区区区间间间 给定长度为\(n\)序列,求\[\sum_{i=1}^{n} \sum_{j=i}^{n} max-min\] 其中\(max\),\(min\)为区间最大,最小值,\(n\l ...
- 牛客网 牛可乐发红包脱单ACM赛 C题 区区区间间间
[题解] 我想到了两种解法. 一种是扫描线+线段树+单调栈. 另一种方法是O(n)的,比较巧妙. 考虑每个数在哪些区间可以作为最小数.最长的区间就是它向左右走,直到有数字比它小,这个可以用单调栈维护. ...
- [nowcoderACM_223C][区区区间间间]
题目链接 思路 考虑用单调栈,栈顶为最大元素.当得到一个新值得时候,将这个值宇栈顶比较.因为栈顶是前面的最大元素.所以只要当前元素比栈顶大,那么肯定比前面的都大.只要将这个元素乘上前面的个数就行了. ...
- TZOJ 5694 区间和II(树状数组区间加区间和)
描述 给定n个整数,有两个操作: (1)给某个区间中的每个数增加一个值: (2)查询某个区间的和. 输入 第一行包括两个正整数n和q(1<=n, q<=100000),分别为序列的长度和操 ...
- LibreOJ 6280 数列分块入门 4(分块区间加区间求和)
题解:分块的区间求和比起线段树来说实在是太好写了(当然,复杂度也高)但这也是没办法的事情嘛.总之50000的数据跑了75ms左右还是挺优越的. 比起单点询问来说,区间询问和也没有复杂多少,多开一个su ...
- LibreOJ 6283 数列分块入门 7(区间加区间乘区间求和)
题解:这道题要打一个乘标记一个加标记,两个标记的优先级是乘法高,所以在乘的时候要将加标记同时乘上一个c,当然,对于每个非完整块一定要记得暴力重构整个块,把加标记和乘标记都初始化. 代码如下: #inc ...
- 使用IBM SVC构建vSphere存储间集群
使用IBM SVC构建vSphere存储间集群 本文目的 本文描述利用IBM SVC来构建Vsphere 存储间集群 解决方案 什么是vMSC? vShpere存储间集群是一个针对VmwarevSpe ...
随机推荐
- Linux操作系统基本知识
1.Linux开发环境 2.GCC 2.1GCC工作流程 预处理:只运行 C 预编译器. 宏去掉了,注释没有了 汇编 编译 链接 2.2GCC常用参数选择 选项 解释 -ansi 只支持 ANSI 标 ...
- openstack之Designate组件,入门级安装(快速)
@ 目录 前言 架构 前提准备 创建 DNS 服务 API 端点 安装和配置组件 验证操作 前言 Designate 是一个开源 DNS 即服务实施,是用于运行云的 OpenStack 服务生态系统的 ...
- 《C++Primary》阅读简要总结
三月份的主要任务之一就是阅读C++Primary这本书,终于在昨天25号下午完成了基础部分的阅读,算是对基础知识整体梳理了一遍,开始看这本书大概可以追溯到去年12月份,在那之前看了C++的入门书籍&l ...
- css的flex布局调试
学习经验-css的flex布局 今天遇到一个小问题 在给三个div布局时,设置父元素display:flex 此时三个div的宽度均为50%,他们并没有超出屏幕的宽度,还是撑满了父元素. 为什么呢? ...
- java实现空心金字塔
前言 最近在学习java,遇到了一个经典打印题目,空心金字塔,初学者记录,根据网上教程,有一句话感觉很好,就是先把麻烦的问题转换成很多的简单问题,最后一一解决就可以了,然后先死后活,先把程序写死,后面 ...
- 万字长文详解HBase读写性能优化
一.HBase 读优化 1. HBase客户端优化 和大多数系统一样,客户端作为业务读写的入口,姿势使用不正确通常会导致本业务读延迟较高实际上存在一些使用姿势的推荐用法,这里一般需要关注四个问题: 1 ...
- 144_Power Pivot贷款之等额本息与等额本金
博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 买房贷款的时候会遇到等额本息与等额本金的问题,今天做了一个两者对比,看看如何选择,来一张对比图. 等额本息的前期 ...
- 以圆类 Circle 及立体图形类 Solid 为基础设计圆柱类 Cylinder
学习内容:以圆类 Circle 及立体图形类 Solid 为基础设计圆柱类 Cylinder 代码示例: import java.util.Scanner;class Point3{ private ...
- Netty是什么,Netty为什么速度这么快,线程模型分析
哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,现在下着大雨看来是去 ...
- Java变量, 常量和作用域
目录 变量 作用域 局部变量 实例变量 类变量 常量 命名规范 视频课程 变量 变量就是可以变化的量 Java是一种强类型的语言, 每个变量都必须声明其类型 Java变量是程序中最基本的存储单元, 其 ...