P10977 Cut the Sequence

P10977 Cut the Sequence

看到题目我们不难想到动态规划,对于每一个点 \(a_i\) 可以求一个 \(pre_i\) 满足 $ \forall j \in[pre_i+1,i]$ $a_l \le a_i $ 且 $ a_i<a_{pre_i} $ 用人话说就是从 \(i\) 往前数第一个大于 \(a_i\) 的数,然后我们可以对于 \(a_i\) 求一个前缀和,这样就能找到对于 \(a_i\) 来说最后一个合法的点 \(lim\)

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

\(f_i= \min(f[j]+ \max a_k) j \in [lim+1,i] k\in [j+1,i]\)

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

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

对于每个点 \(a_i\) 我们先将线段树上点 \(i\) 的权值更新为 \(f_{i-1}\) 然后更新 \([pre,i]\) 区间的 \(max\)\(a_i\)
然后直接在线段树上查询 \(f_i\) 就好了

然后这题就愉快的做完了

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 @ 2024-12-06 12:04  liuboom  阅读(33)  评论(0)    收藏  举报