您的位置:首页 > Web前端

POJ[2796]Feel Good 单调栈

2017-08-30 21:59 337 查看
题目链接:http://poj.org/problem?id=2796

题目大意:给定一个长度为n的序列,让你在n个数中取一段连续的区间,使这个区间中的最小值乘以这个区间元素和的值最大,并输出左右端点

对于每一个数ai,作为某一段区间的最小值,求出保证ai最小,它最左可以扩展到Li,最右可以扩展到Ri

暴力的话需要n2,这样显然是超时的

我们可以用单调递增栈来维护,从左到右考虑每一个新加入的数ai,如果能使栈中数x弹出,则数x最右可以扩展到i−1(因为如果前面还有比它小的数,数x就不会存在于栈中),这样我们就可以求出每个数i向右可以扩展的最远距离Ri,求Li只需将该过程反过来即可

统计答案可以用前缀和q[]来统计,则每一个数作为最小值的答案就是a[i]∗(q[R[i]]−q[L[i]−1])

注意答案有0的情况,可以讲ans初始为-1,也可以讲答案更新条件改成a[i]∗(q[R[i]]−q[L[i]−1])≥ans

还有这道题爆int

代码如下:

#include<algorithm>
#include<cstdio>
#define N 100050
#define int long long
//注意这道题爆int
using namespace std;
int a
,L
,R
,q
,n,top,ans,l,r;
struct Data{
int x,k;
Data(int _=0,int __=0):x(_),k(__){}
}s
;
main(){
ans=-1;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",a+i),q[i]=q[i-1]+a[i];
for(int i=1;i<=n;i++){
if(!top) {s[++top]=Data(i,a[i]);continue;}
if(a[i]>=s[top].k);
else while(a[i]<s[top].k && top) R[s[top--].x]=i-1;
s[++top]=Data(i,a[i]);
}//求R数组
while(top) R[s[top--].x]=n;//注意这里要将没出栈的元素R值赋为n

for(int i=n;i>=1;i--){
if(!top) {s[++top]=Data(i,a[i]);continue;}
if(a[i]>=s[top].k);
else while(a[i]<s[top].k && top) L[s[top--].x]=i+1;
s[++top]=Data(i,a[i]);
}//求L数组
while(top) L[s[top--].x]=1;//同上
for(int i=1;i<=n;i++)
if(a[i]*(q[R[i]]-q[L[i]-1])>ans){//统计答案,如果ans初值为0,将>ans改为>=ans即可
ans=a[i]*(q[R[i]]-q[L[i]-1]);
l=L[i];r=R[i];
}
printf("%lld",ans);
printf("\n%lld %lld\n",l,r);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: