题目:
题意:
在 n n n个数中分出若干个区间使得区间的价值总和最大
分析:
在新加入一个数时,我们能够产生影响的范围是最近一个比自己小的那个数,所以我们用一个单调栈来维护每个数的那个数
设
f
i
f_i
fi表示做到
i
i
i时最优解,加入一个数时,我们有两种选择,一个是自己将比自己大的数都合并在一起,整个区间的答案就是自己,另一种则是选择默默无名,乖乖的加入一个有比自己小的区间内
对于第一个选择,我们如何确定最优解时到底是如何安排区间的呢
我们之前的
f
f
f都已经确定了,因为
f
f
f保存的就是
i
i
i之前的最优安排方案,所以我们取
m
a
x
{
f
}
max\{f\}
max{f},而在这个最优安排下可能会存在没有被放入其他区间的数,那就跟当前这个数一起作为一个新区间,然后价值就带入到公式里计算就好了
因为我们覆盖过的数是已经确定的,从而每个数都只会被覆盖一次,这样就是
O
(
n
)
O(n)
O(n)的优秀复杂度
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LZX Mu
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
LL n,a,b,c,d;
LL get(LL x) {return a*x*x*x+b*x*x+c*x+d;}
struct node{
LL maxf,id,ans;
}s[200005];
LL x[200005],len=0,f[200005];
int main()
{
freopen("min.in","r",stdin);
freopen("min.out","w",stdout);
n=read(),a=read(),b=read(),c=read(),d=read();
for(LL i=1;i<=n;i++) x[i]=read();
for(LL i=1;i<=n;i++)
{
LL w=f[i-1];
while(len&&x[s[len].id]>=x[i]) w=max(w,s[len].maxf),len--;
s[++len].maxf=w;s[len].id=i;
if(len>1) s[len].ans=max(w+get(x[i]),s[len-1].ans);
else s[len].ans=w+get(x[i]);
f[i]=s[len].ans;
}
cout<<f[n];
return 0;
}