poj2796-动态规划思想+回溯&&单调栈第一题

一般来说,有动态规划思想的都是动态规划水题。
当然,前提是你完全理解了动态规划思想
给定你一些数,要求你找一个区间,要求这个区间内的数的和乘以这个区间内最小的数,要求这个积最大。
简直蒙蔽,
后来发现说单调栈也能写,但是不会单调栈。。
看懂题解了,
就是先没个数左边的数(这是确定的,并且要从左往右求,这样可以利用前面的结果。)
往右也是这样。
还有一点画龙点睛的就是
看数据范围,改long long;
2 首尾的初始化要搞明白,不然会出事的

#include <bits/stdc++.h>
using namespace std;
/*poj 2796 feel food
给定一个区间,求这个区间的和,再乘以这个区间内最小的,要求结果最大。
dp思想进行的操作
我不知道他叫什么,不过应该和单调栈不一样。
单调栈也可以写哦
是用dp的思想,而那个 lr的数组好想kmp的next数组。
*/
long long  a[100006];
int lef[100006];
int r[100006];
long long sum[100006];
int main()
{   freopen("feelgood.in","r",stdin);
     freopen("feelgood.out","w",stdout);
    int n;

   scanf("%d",&n);
       sum[0]=0;
   for(int i=1;i<=n;i++)
   {  scanf("%lld",&a[i]);
       sum[i]=sum[i-1]+a[i];
   }
    a[0]=-9999;
    a[n+1]=-99999;
    //初始化过程,把这个结果的
    for(int i=1;i<=n;i++)
    {   for(int j=i-1;j>=0;)
        {   if(a[j]<a[i])
             {lef[i]=j+1;//如果出现一个左边一个比他还小的,、
             //那么就结束就好了
             break;
             }
             else
             {  //left[i]=left[j]
                 j=lef[j]-1;//把
             }

        }

    }
    //for(int i=0;i<=n;i++)
        //printf("%d  ",lef[i]);
    //cout<<endl;
    for(int i=n;i>=1;i--)
    {   for(int j=i+1;j<=n+1;)
          {    if(a[j]<a[i])
                {r[i]=j-1;
                break;//算出来一个数的最右后,再计算下一个
                }
               else
               {   j=r[j]+1;
                   //if(i==2)
                    //cout<<j<<endl;
               }
          }
    }
    long long  all=(sum[r[1]]-sum[lef[1]-1])*a[1];
     //cout<<all<<endl;
    long long  ans=0;
     int ri=r[1];
     int l=lef[1];//初始化应该是他的最左和最右。
   for(int i=2;i<=n;i++)
    {    ans=(sum[r[i]]-sum[lef[i]-1])*a[i];

         if(all<ans)
             {all=ans;
             ri=r[i];
             l=lef[i];
             }
    }
    cout<<all<<endl;
     cout<<l<<" "<<ri<<endl;
    return 0;
}

方法2 利用单调栈
单调栈是一种数据结构,保证栈顶元素是最小的。
用来求一个数组中某个数占的区间。
别人说这是单调栈的经典题。。
维护一个单调递增的栈就行,
如果要加的元素比他就行。比他小。就更新他的左延伸。
(我已经比他小了,肯定比他范围内的任何数最小啊。)
同时如果还有数,那么就更新他的右延伸。cin竟然会tle。。
另外有一种特殊化的情况。所以ans的要设置为第一个数。哈

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <stack>
using namespace std;
const int maxn=100006;
typedef  long long ll;
struct node
{  ll  v;
    ll l,r;
    ll k;
};
int main()
{   int m;
    ll sum[maxn];
    ll a[maxn];
    scanf("%d",&m);
    sum[0]=0;
    for(int i=1;i<=m;i++)
    {scanf("%lld",&a[i]);
     sum[i]=sum[i-1]+a[i];
    }
     stack<node>s;
    node tmp;
       tmp.k=1;
       tmp.v=a[1];
       tmp.l=1;
       tmp.r=1;
        s.push(tmp);
       ll ans=a[1];
        long long ll=1;
        long long  rr=1;
     for(int i=2;i<=m;i++)
     {    tmp.r=tmp.l=1;
         tmp.k=i;
         tmp.v=a[i];
         while(!s.empty()&&s.top().v>tmp.v)
         {    node u=s.top();
               s.pop();
               if(!s.empty())
                 s.top().r+=u.r;
                 tmp.l+=u.l;
               long long  sum1=u.v*(sum[u.k+u.r-1]-sum[u.k-u.l]);
                 //cout<<sum1<<"^^"<<u.v<<endl;
                 if(sum1>ans)
                 {   ans=sum1;
                     ll=u.k-u.l+1;
                     rr=u.k+u.r-1;
                 }
         }
         s.push(tmp);
     }
     //开始是维护一个单调栈,把一些位置尴尬的数给去掉了
     //但是里面还保留着一些数,需要把他们清掉
      while(!s.empty())
      {   tmp=s.top();
           s.pop();
           if(!s.empty())
             s.top().r+=tmp.r;
           long long sum1=tmp.v*(sum[tmp.k+tmp.r-1]-sum[tmp.k-tmp.l]);
         //cout<<tmp.k<<".."<<sum1<<endl;
           if(sum1>ans)
           {    ans=sum1;
                ll=tmp.k-tmp.l+1;
                rr=tmp.k+tmp.r-1;
           }
      }
       if(m==0) ll=rr=ans=0;
         printf("%lld\n%lld %lld\n",ans,ll,rr);
    return 0;
}





“`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值