题目描述:
输入:
输出: 输出一个数
样例:
input :
5
7 8 5 6 7
output:
86
大致思路:
使用单调栈来进行求解,
如上图所示,我们计算每个元素的贡献度
左贡献度:就是寻找该元素右边第一个比它小的元素,然后其坐标之差就是其贡献度,
右贡献度:就是寻找该元素左边第一个比它小的元素,然后其坐标之差就是其贡献度,
为什么左右贡献度要相乘呢? 因为贡献度就是在上述问题中的计算次数,
我们用 5 举例子 对于求和公式 i=1,j = 3,4,5 时,5各被计算一次;i=2, j = 3,4,5 时,5各被计算一次;当i=3 时,j = 3,4,5 时,5各被计算一次; 所以一共出现了9次。
代码源码:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const ll N = 2e5+7;
ll a[N],sum[N];//sum用来储存a[i]贡献的次数
void solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
ll suma=0;
stack<int > st;
for(int i=1;i<=n;i++){ //计算向左贡献的次数
while(st.size()&&a[st.top()] >= a[i]){ //当栈不为空并且栈顶元素大于等于a[i]的时候,
//我们就找到了右边第一个比栈顶小的元素,就可
//以计算出贡献次数,并将其出站
sum[st.top()] = i - st.top();
st.pop();
}
st.push(i);
if(i>=n){ //当所有元素都扫一遍之后,发现还有栈内还有元素,那么我们就要对未贡献的元素求其贡献度,为什么是i-top()+1呐? 因为每个站内元素对其贡献度都是到最末尾的那个元素
while(st.size()){
sum[st.top()] = i - st.top()+1;
st.pop();
}
}
}
st = stack<int>();
for(int i=n;i>=1;i--){ //计算向右贡献的次数
while(st.size()&&a[st.top()] > a[i]){
sum[st.top()] *= (st.top()-i);
st.pop();
}
st.push(i);
if(i<=1){
while(st.size()){
sum[st.top()] *= (st.top()-i+1);
st.pop();
}
}
}
for(int i=1;i<=n;i++) suma+=sum[i]*a[i];
cout<<suma;
}
int main()
{
solve();
return 0;
}