思路:
- 自己的想法跟题解一样,也是从左右两边找到最远能扩展的位置。但这样复杂度一定是O(n^2)
- 显然会超时,于是自己发现除了这个思路没有好办法了,于是去学习一波新技能√ ---- 单调栈!
- 单调栈其实精湛的不是用栈去实现,而是一种思维,用这种单调的思维去降低复杂度。
- 以这个题为例,我们可以给每个位置pos,记录它向右最远的扩展距离R[pos],向左最远的扩展距离L[pos]。
- 举个栗子:
- 如果从位置i 想左进行扩展,第一个index = i-1,如果val[index]>=val[i],证明可以继续向左扩展,这时候index不需要向前走一步,而是走l[index]步,中间的这些一定也是>=val[i]的。即是单调的!酱紫就少了很多冗余的判断,使得整个过程几乎是单调的。这就是单调栈精髓的地方!
- 所以我们预处理好每个位置,然后找到max(l[i]+r[i]+1)*val[i] 即可
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define IO ios_base::sync_with_stdio(0),cin.tie(0)
#define pb(x) push_back(x)
#define sz(x) (int)(x).size()
#define abs(x) ((x) < 0 ? -(x) : x)
#define mk(x,y) make_pair(x,y)
#define fin freopen("in.txt","r",stdin)
#define fout freopen("out.txt","w",stdout)
typedef long long ll;
typedef pair<int,int> P;
const int mod = 1e9+7;
const int maxm = 1e8+5;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;
ll a[maxn];
ll l[maxn];
ll r[maxn];
int main()
{
// fin;
// IO;
int n;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
int index = i-1;
l[i] = 1;
while(a[i]<=a[index] && index>=1){
l[i]+=l[index];
index-=l[index];
}
}
for(int i=n;i>=1;i--){
int index = i+1;
r[i] = 1;
while(a[i]<=a[index] && index<=n)
{
r[i]+=r[index];
index+=r[index];
}
}
ll res = 0;
for(int i=1;i<=n;i++){
res = max(a[i]*(l[i]+r[i]-1),res);
}
printf("%lld\n",res);
}
return 0;
}