poj2796 Feel Good 单调栈

来源:互联网 发布:程序员不培训班 编辑:程序博客网 时间:2024/05/03 23:17

题目大意:

题意:给你一段区间,需要你求出(在这段区间之类的最小值*这段区间所有元素之和)的最大值......

例如:

63 1 6 4 5 2

以4为最小值,向左右延伸,6 4 5  值为60.......

思路:

单调栈的原理:它就是以某一个值为最小(最大)值,向这个值的两侧延伸,遇到大于它(小于它)的值,就将它延伸的范围扩大,当然,一般来说,要这样做的算法复杂度为o(n^2),但是借助栈,维护其单调增(减),就可以在o(n)的时间复杂度解决这个问题。将一元素加入栈时,

本题用递增栈

先判断它是否大于栈顶元素,

  若小于等于栈顶元素,

          栈顶元素出栈, 出栈元素的右端点就确定为当前元素-1

    若是大于栈顶元素,加入栈。栈顶元素+1就是当前节点的左边界,如果栈为空,则左边界是起点1,



例如:3 1 6 4 5 2

手工栈s,将s【0】=0;

 把3>0,下标1 加入栈,a[1].l=1;

1<3,  下标1出栈,a[1].r=1;

下标2入栈 , a[2].i=1;

下标3入栈  a[1],<a[3], 3入栈 a[3].l=s.[top]+1=2;

依次进行……


这个题目花了好长时间调试,,结果早就用了long long ,根据网上ac的题目对拍,因为结果不唯一,改了几个版本,和别人的对拍都一样,自己提交就是不过。

后来不知看了哪个人的说明,比较最值的时候要<=才过,改过来,终于过了。



#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
const int maxn=100010;
long long a[100010];
int l[100010],r[100010],s[100010]={0},n,ansl,ansr,top;
long long sum[100010]={0},ans=-1;
int main(){

int i,j;
scanf("%d",&n);

for(i=1;i<=n;i++){
scanf("%I64d",&a[i]);
sum[i]=sum[i-1]+a[i];
l[i]=r[i]=i;
}

a[0]=a[n+1]=-1;
top=0;
s[0]=0;
for(i=1;i<=n+1;i++){

while(top&&a[i]<=a[s[top]]){//a[i]<栈顶,出栈 
 r[s[top]] =i-1;//找出栈顶元素的下标右端点 
 top--;

l[i]=s[top]+1;  
   s[++top]=i;
}

long long tmp;
for(i=1;i<=n;i++){//根据左右端点求值。 
tmp=1LL*(sum[r[i]]-sum[l[i]-1])*a[i];
if(tmp>=ans){
ans=tmp;
ansl=l[i];
ansr=r[i];

}
}
       printf("%lld\n", ans);
       printf("%d %d\n", ansl, ansr);
return 0;
}

大约运行800ms


也可以用stack, 1100多ms

#include<stdio.h>
#include<math.h>
#include<iostream>
#include<stack>
using namespace std;
const int maxn=100010;
long long a[100010];
int l[100010],r[100010],n,ansl,ansr,top;

long long  sum[100010]={0},ans=-1;

int main(){
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
l[i]=r[i]=i;
}
a[0]=a[n+1]=-1;

stack<int>s;   
for(i=1;i<=n+1;i++){
while(!s.empty()&&a[i]<=a[s.top()]  ){//a[i]<栈顶,出栈 
 r[s.top()] =i-1;//找出栈顶元素的下标右端点 
 s.pop();

if(!s.empty())l[i]=s.top()+1;  
else l[i]=1;
   s.push(i);



long long tmp;
for(i=1;i<=n;i++){

tmp=(sum[r[i]]-sum[l[i]-1])*a[i];
if(tmp>=ans){
ans=tmp;
ansl=l[i];
ansr=r[i];
}
}
printf("%lld\n", ans);
  printf("%d %d\n", ansl, ansr);
return 0;
}




0 0
原创粉丝点击