JZOJ 6305.最小值【思维】【dp】

33 篇文章 0 订阅


题目:

传送门


题意:

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值