P10977 Cut the Sequence

P10977 Cut the Sequence

看到题目我们不难想到动态规划,对于每一个点 ai 可以求一个 prei 满足 j[prei+1,i] alaiai<aprei 用人话说就是从 i 往前数第一个大于 ai 的数,然后我们可以对于 ai 求一个前缀和,这样就能找到对于 ai 来说最后一个合法的点 lim

然后我们思考一下状态转移:

fi=min(f[j]+maxak) j[lim+1,i] k[j+1,i]

然后我们会发现右边那个东西可以用线段树来维护,f 支持单点修改,max 支持区间赋值

开一个线段树维护三个数:f,mi,ans 分别表示区间内最小化的 f ,最小化后的 max ,和区间答案

对于每个点 ai 我们先将线段树上点 i 的权值更新为 fi1 然后更新 [pre,i] 区间的 maxai
然后直接在线段树上查询 fi 就好了

然后这题就愉快的做完了

Code:

#include<bits/stdc++.h>
#define ll long long
const int N=1e5+5;
const ll inf=1e17;
using namespace std;
//Segment_Tree
#define ls x<<1
#define rs x<<1|1
struct Segmeng_Tree{
struct Tree{
ll ans,f,mi;
int l,r;
}t[N<<2];
void pushup(int x)
{
t[x].ans=min(t[ls].ans,t[rs].ans);
t[x].f=min(t[ls].f,t[rs].f);
return;
}
void upd(int x){t[x].ans=t[x].f+t[x].mi;}
void pushdown(int x)
{
if(t[x].mi==inf)return ;
t[ls].mi=t[rs].mi=t[x].mi;
upd(ls);upd(rs);
t[x].mi=inf;
}
void build(int x,int l,int r)
{
t[x]=(Tree){inf,inf,inf,l,r};
if(l==r)return;
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void upd_mi(int x,int L,int R,ll mi)
{
if(L<=t[x].l&&t[x].r<=R)
{
t[x].mi=mi;
upd(x);
return;
}
int mid=t[x].l+t[x].r>>1;
pushdown(x);
if(L<=mid)upd_mi(ls,L,R,mi);
if(mid<R) upd_mi(rs,L,R,mi);
pushup(x);
}
void upd_f(int x,int pos,ll w)
{
if(t[x].l==t[x].r)
{
t[x].f=w;
return ;
}
int mid=t[x].l+t[x].r>>1;
pushdown(x);
if(pos<=mid)upd_f(ls,pos,w);
if(mid<pos) upd_f(rs,pos,w);
pushup(x);
}
ll query(int x,int L,int R)
{
if(L<=t[x].l&&t[x].r<=R)
{
return t[x].ans;
}
int mid=t[x].l+t[x].r>>1;
pushdown(x);
ll res=inf;
if(L<=mid)res=min(res,query(ls,L,R));
if(mid<R) res=min(res,query(rs,L,R));
return res;
}
}T;
#undef ls
#undef rs
//Segment_Tree
int n,m,st=1,ed=0;
int q[N],pre[N];
ll a[N],sum[N],f[N];
void work()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(a[i]>m){cout<<"-1";return;}
while(st<=ed&&a[q[ed]]<a[i]){
ed--;
}
pre[i]=q[ed];
q[++ed]=i;
sum[i]=sum[i-1]+a[i];
}
T.build(1,1,n);
//return;
for(int i=1;i<=n;i++)
{
T.upd_f(1,i,f[i-1]);
if(pre[i]<i)T.upd_mi(1,pre[i]+1,i,a[i]);
int l=lower_bound(sum,sum+1+i,sum[i]-m)-sum;// sum[i]-sum[l]>m
if(l<i)f[i]=T.query(1,l+1,i);
}
printf("%lld",f[n]);
}
int main()
{
//freopen("P10977.in","r",stdin);
//freopen("P10977.out","w",stdout);
work();
}
posted @   liuboom  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示