吸氧羊的StarryCoding之旅
吸氧羊终于注册了一个StarryCoding账号!(她很开心)
但是吸氧羊忘记了它的密码,她想起你是计算机大师,于是就来请教你。
她虽然不记得密码了,但她记得一个数组,而这个密码就是这个数组中所有区间的最大值之和。
你赶快求出来吧,她太想进去玩了!
输入描述
第一行一个整数 n n n,表示数组 a a a的长度。( 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105)
第二行 n n n个整数表示数组 a a a中的元素。( 1 ≤ a i ≤ 1 0 8 1 \leq a_i \leq 10^8 1≤ai≤108)
输出描述
一行一个整数表示结果。
输入样例
5
1 1 1 1 1
输出样例
15
解释
一共有15个区间,每个区间的最大值都是1,它们的和是15。
思路
首先,定义一些变量和数组,其中n
是数组的长度,a
是输入的数组,l
和r
用于存储每个元素左侧和右侧的边界位置,stk
是一个栈,用于辅助计算。接着,从标准输入流读取n
和a
的值。
然后,从左向右遍历数组。对于每个元素,如果栈不为空且栈顶元素小于当前元素,则弹出栈顶元素,直到栈顶元素不小于当前元素或栈为空。然后,如果栈不为空,将栈顶元素的位置+1作为当前元素的左边界,否则,左边界为1。最后,将当前元素的位置入栈。
清空栈后,从右向左遍历数组。对于每个元素,如果栈不为空且栈顶元素小于等于当前元素,则弹出栈顶元素,直到栈顶元素大于当前元素或栈为空。然后,如果栈不为空,将栈顶元素的位置-1作为当前元素的右边界,否则,右边界为n
。最后,将当前元素的位置入栈。
最后,遍历数组,计算并累加每个元素的贡献值,即(i - l[i] + 1) * (r[i] - i + 1) * a[i]
。其中,i - l[i] + 1
是当前元素在左侧的区间数量,r[i] - i + 1
是在右侧的区间数量,a[i]
是当前元素的值。所以,每个元素的贡献值就是其值乘以其在所有区间中出现的次数。最后,将累加的结果输出。
注意
- 由于可能会出现重复数据,应该把a[i]作为区间[l,r]中最左边的最大值。在从左向右遍历数组时,若
a[stk.top()] < a[i]
则出栈。在从右向左遍历数组时,若a[stk.top()] <= a[i]
则出栈。否则在计算贡献值时,重复数据会导致重复计算。 - 计算并累加每个元素的贡献值时,每个元素的贡献值就是其值乘以其在所有区间中出现的次数,别忘了乘上
a[i]
。
AC代码
#include <algorithm>
#include <iostream>
#include <stack>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
const int N = 1e6 + 7;
int n;
ll a[N];
ll l[N], r[N];
stack<int> stk;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// 从左往右
for (int i = 1; i <= n; i++) {
while (stk.size() && a[stk.top()] < a[i]) {
stk.pop();
}
if (stk.size()) {
l[i] = stk.top() + 1;
} else {
l[i] = 1;
}
stk.push(i);
}
// 清空栈
while (stk.size()) {
stk.pop();
}
// 从右往左
for (int i = n; i >= 1; i--) {
while (stk.size() && a[stk.top()] <= a[i]) {
stk.pop();
}
if (stk.size()) {
r[i] = stk.top() - 1;
} else {
r[i] = n;
}
stk.push(i);
}
// 计算贡献
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans += (i - l[i] + 1) * (r[i] - i + 1) * a[i];
}
cout << ans << "\n";
return 0;
}