http://poj.org/problem?id=2796
题意:求n个数的和乘以这n个数中的最小值的积最大的数,以及其范围。
思路:求每一个数两边的比其大的数的和,再乘以这个数。还有一个范围,用单调栈找以及记录。
这个题和2559差不多,就是多了一个对数字的求和。
#include <stdio.h>
#include <iostream>
#include <stack> #define x 100010 using namespace std; stack<long long >s;
long long l[x],r[x],a[x],sum,ans,z[x],m,loc; int main(){
int n;
scanf("%d",&n);
ans=;
z[]=,r[]=,l[]=,l[]=,r[n]=n; //要考虑案例是1 0 的情况。
for(int i=;i<=n;i++){ scanf("%lld",&a[i]);
z[i]+=z[i-]+a[i]; //z[m]-z[n-1]就是从m到n的a[i]之和。
}
a[]=-,a[n+]=-;
while(!s.empty()){ s.pop();
}
s.push(); for(int i=;i<=n;i++){ for(m=s.top();a[m]>=a[i];m=s.top()) s.pop(); l[i]=m+; s.push(i);
}
while(!s.empty()) s.pop(); s.push(n+); for(int i=n;i>;i--){
sum=; for(m=s.top();a[m]>=a[i];m=s.top())
s.pop();
r[i]=m-;
s.push(i);
if((z[r[i]]-z[l[i]-])*a[i]>ans) {ans=(z[r[i]]-z[l[i]-])*a[i];loc=i;}
} printf("%lld\n%lld %lld\n",ans,l[loc],r[loc]);
return ;
}