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