P9871 [NOIP2023] 天天爱打卡

题目传送门

首先我们来考虑一下原始的dp方程

设 \(dp_i\) 为第 \(i\) 天时的最大能量值,\(w_{i,j}\) 为从第 \(i\) 天到第 \(j\) 天能获得的能量值

那么可以得到转移方程 \(dp_i=max(dp_{j-1}-(i-j+1)*d+w_{i,j})(max(1,i-k+1)\le j\le i)\)

此时复杂度为 \(O(nmk)\)

我们来考虑如何优化

优化一:离散化

我们注意到只有刚好跑完一个区间才是最优的,所以上述方程中 \(j\) 的取值必定是左右端,于是离散化

优化二:线段树

我们考虑一个区间 \([l,r]\),显然受到这个区间加成的 \(w_{i,j}\) 一定满足 \(i\le l,j\ge r\)

那么我们就可以将所有区间按右端排序,求 \(dp_i\) 时,令所有 \(w_{k,i}(1\le k \le l_p,r_p= i)\) 加上 \(v_p\),这显然是线段树

我们再将转移方程变形,得到 \(dp_i=max(dp_{j-1}+(j-1)*d-i*d+w_{i,j})\),显然我们可以用线段树维护 \(dp_{j-1}+(j-1)*d\),再将两个线段树合并就可以解决问题

#include<bits/stdc++.h>
using namespace std;
#define ls p*2
#define rs p*2+1
#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
#define ll long long
#define M 500005
#define INFLL 0x3f3f3f3f3f3f3f3f
ll seg[M*4],tag[M*4],mp[M],n,m,k,d;
struct node{
	ll l,r,val;
}a[M];
ll len,x,y,w,c,t;
ll get_id(ll x){return lower_bound(mp+1,mp+len+1,x)-mp;}
void push_down(ll l,ll r,ll p){
	seg[p]+=tag[p];
	if(l!=r) tag[ls]+=tag[p],tag[rs]+=tag[p];
	tag[p]=0;
}
void push_up(ll l,ll r,ll p){
	if(l!=r) push_down(lson),push_down(rson);
	seg[p]=max(seg[ls],seg[rs]);
}
void build(ll l,ll r,ll p){
	tag[p]=seg[p]=0ll;
	if(l==r) return;
	build(lson),build(rson);
	push_up(l,r,p);
}
void update(ll l,ll r,ll p,ll L,ll R,ll v){
	push_down(l,r,p);
	if(L<=l&&r<=R){
		tag[p]+=v;
		return;
	}
	if(mid>=L) update(lson,L,R,v);
	if(mid<R) update(rson,L,R,v);
	push_up(l,r,p);
}
ll query(ll l,ll r,ll p,ll L,ll R){
	push_down(l,r,p);
	if(L<=l&&r<=R) return seg[p];
	ll res=-INFLL;
	if(mid>=L) res=max(res,query(lson,L,R));
	if(mid<R) res=max(res,query(rson,L,R));
	return res;
}
bool cmp(node c,node d){
	return c.r<d.r;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>c>>t;
	while(t--){
		len=0;
		cin>>n>>m>>k>>d;
		for(ll i=1;i<=m;i++){
			cin>>x>>y>>w;
			a[i]={x-y+1,x,w};
			mp[++len]=a[i].l-1,mp[++len]=a[i].r+1;
		}
		sort(mp+1,mp+len+1);
		len=unique(mp+1,mp+len+1)-mp-1;
		build(1,len,1);
		for(ll i=1;i<=m;i++){
			a[i].l=get_id(a[i].l-1);
			a[i].r=get_id(a[i].r+1);
		}
		sort(a+1,a+m+1,cmp);
		ll e=1,ans=0,lim=0;
		update(1,len,1,1,1,mp[1]*d);
		for(ll i=2;i<=len;i++){
			while(e<=m&&a[e].r==i){
				update(1,len,1,1,a[e].l,a[e].val);
				e++;
			}
			for(;mp[i]-mp[lim]-1>k;lim++); 
			ans=max(ans,query(1,len,1,lim,i-1)-(mp[i]-1)*d);
			update(1,len,1,i,i,ans+mp[i]*d);
		}
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2026-10-30 14:53  Rainesxiao  阅读(4)  评论(0)    收藏  举报