×

第五篇:P1295

题解补完计划:第四篇

原题题面

显然, 我们可以 DP,我们定义 \(dp_i\) 表示前 \(i\) 个的书的最小和。

那么我们可以写出转移:
\(dp_i = min_{j=0}^{i-1} dp_j + max_{k=j+1}^{i} h_i\)。
观察这个式子,我们发现对于 \(i\), \(h_i\) 是最大值时是自己向左最近的大于自己的地方,这个可以用单调栈解决,问题变为在允许动态修改区间, 区间查询最小值,用线段树解决就可以了。(注意还有一个限制是每段和小于等于 \(m\), 这个我们可以找出每个 \(i\) 向左最远到哪里,然后查询的时候注意一下就可以了)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
#define inf 0x7ffffffffffffff
intl dp[N], sum[N], a[N], n, m;
struct Seg{
	intl tr[N<<2], mx[N<<2], num[N<<2], tag[N<<2];
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid ((l+r)>>1)
	Seg() {
		memset(tr,0x7f,sizeof tr), memset(mx,0,sizeof mx), memset(num,0,sizeof num);
	}
	void pushdown(intl p) {
		if(tag[p]) {
			tag[lc] = max(tag[lc],tag[p]);
			tag[rc] = max(tag[rc],tag[p]);
			mx[lc] = max(mx[lc],tag[p]), mx[rc] = max(mx[rc],tag[p]);
			tr[lc] = num[lc] + mx[lc], tr[rc] = num[rc] + mx[rc];
			tag[p] = 0;
		}
	}
	void updata(intl p,intl l,intl r,intl ll,intl rr,intl d) {
		if(rr < l || r < ll) return ;
		if(ll <= l && r <= rr) return tag[p] = max(d,tag[p]),mx[p] = max(mx[p],d),tr[p] = num[p] + mx[p],void();
		pushdown(p);
		updata(lc,l,mid,ll,rr,d),updata(rc,mid+1,r,ll,rr,d);
		tr[p] = min(tr[lc], tr[rc]);
		mx[p] = max(mx[lc],mx[rc]);
		num[p] = min(num[lc],num[rc]);
	}
	void modify(intl p,intl l,intl r,intl pos,intl d) {
		if(pos < l || r < pos) return ;
		if(pos <= l && r <= pos) return num[p] = d, tr[p] = num[p] + mx[p],void();
		pushdown(p);
		modify(lc,l,mid,pos,d), modify(rc,mid+1,r,pos,d);
		tr[p] = min(tr[lc],tr[rc]);
		mx[p] = max(mx[lc],mx[rc]);
		num[p] = min(num[lc],num[rc]);
	}
	intl query(intl p,intl l,intl r,intl ll,intl rr) {
		if(rr < l || r < ll) return inf;
		if(ll <= l && r <= rr) return tr[p];
		pushdown(p);
		return min(query(lc,l,mid,ll,rr),query(rc,mid+1,r,ll,rr));
	}
}seg;
intl sta[N],top,las[N];
int main() {
	n=read(), m=read();
	For(i,1,n) a[i] = read(), sum[i] = sum[i-1] + a[i];
	dp[0] = 0;seg.modify(1,0,n,0,0);
	sta[++top] = 1;
	For(i,2,n) {
		while(top && a[sta[top]] < a[i]) top --;
		if(top) las[i] = sta[top];
		sta[++top] = i;
	}
	For(i,1,n) {
		intl pos = lower_bound(sum,sum+n+1,sum[i]-m)-sum;
		seg.updata(1,0,n,las[i],i-1,a[i]);
		dp[i] = seg.query(1,0,n,pos,i-1);
		seg.modify(1,0,n,i,dp[i]);
	}
	printf("%lld\n",dp[n]);
	return 0;
}

posted @ 2026-10-05 17:24  shiori123  阅读(3)  评论(0)    收藏  举报