两种思路:
1 单调栈:维护一个单调非递减栈,当栈为空或者当前元素大于等于栈顶元素时就入栈,当前元素小于栈顶元素时就出栈,出栈的同时计算当前值,当前值所包含的区间范围为从当前栈顶元素到当前元素i的距离加上栈顶元素到第二个栈顶元素的距离。
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1E5+7; ll arr[N]; int main(){ ll n; while(cin>>n,n){ ll ans=0; stack<ll >st; for(ll i=1;i<=n;i++) cin>>arr[i]; arr[n+1]=0; for(ll i=1;i<=n+1;i++){ if(st.empty()||arr[st.top()]<=arr[i]) st.push(i); else { ll c=st.top(); while(st.size()&&arr[c]>arr[i]){ st.pop(); if(st.empty()) ans=max(ans,arr[c]*(i-1)); else { ans=max(ans,(i-st.top()-1)*arr[c]); c=st.top(); } } st.push(i); } } cout<<ans<<endl; } return 0; }
2 dp
维护两个数组left和right,left[i]表示元素i向大于当前元素向左的最大连续延伸。right[i]同理。
转移方式:j=left[j]-1,j=right[j]+1。然后遍历每个元素ans=max(ans,(right[i]-left[i]+1)*arr[i])
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1E5+7; ll arr[N]; ll left1[N]; ll right1[N]; int main(){ ll n; while(scanf("%lld",&n)!=EOF&&n){ for(ll i=1;i<=n;i++){ scanf("%lld",&arr[i]); left1[i]=right1[i]=i; } for(ll i=1;i<=n;i++){ ll j=i; while(j>=1&&arr[i]<=arr[j]) j=left1[j]-1; left1[i]=j+1; } for (ll i=n-1; i>=1; i--) { ll j=i; while (j<=n && arr[i]<=arr[j]) j=right1[j]+1; right1[i]=j-1; } ll ans=0; for(ll i=1;i<=n;i++){ ans=max(ans,(right1[i]-left1[i]+1)*arr[i]); }printf("%lld ",ans); } return 0; }