题意:给一个非负整数序列,求哪一段区间的权值最大,区间的权值=区间所有数的和×区间最小的数。
用单调非递减栈在O(n)计算出序列每个数作为最小值能向左和向右延伸到的位置,然后O(n)枚举每个数利用前缀和O(1)计算出以这个数为最小值能得到的最大的区间权。
以前写的单调栈,三个if分支,写得繁繁杂杂的;现在重写了一下,感觉代码简洁了不少:
1 #include<cstdio> 2 using namespace std; 3 #define MAXN 111111 4 int stack[MAXN],top; 5 int l[MAXN],r[MAXN]; 6 long long a[MAXN],s[MAXN]; 7 int main(){ 8 int n; 9 while(~scanf("%d",&n)){ 10 for(int i=1; i<=n; ++i) scanf("%d",a+i),s[i]=s[i-1]+a[i]; 11 a[++n]=-1; 12 for(int i=1; i<=n; ++i){ 13 l[i]=r[i]=i; 14 while(top && a[stack[top]]>a[i]){ 15 l[i]=l[stack[top]]; 16 r[stack[top]]=i-1; 17 --top; 18 } 19 if(top && a[stack[top]]==a[i]) l[i]=l[stack[top]]; 20 stack[++top]=i; 21 } 22 int x,y; 23 long long res=-1; 24 for(int i=1; i<n; ++i){ 25 if(res<(s[r[i]]-s[l[i]-1])*a[i]){ 26 res=(s[r[i]]-s[l[i]-1])*a[i]; 27 x=l[i]; y=r[i]; 28 } 29 } 30 printf("%lld\n%d %d\n",res,x,y); 31 } 32 return 0; 33 }
时间: 2024-10-05 06:17:25