[NOIP2023] 天天爱打卡

传送门

真是写力竭了。

题目思路

简单的转移:\(f_i=\max\limits_{j=i-k}^{i-1} \{g_{j-1}-(i-j)\cdot d+\sum v_p\}\)。其中 \(g_i=\max\limits_{j=1}^{i} f_j\)。

虽然说这是一道线段树维护 dp 的经典题,但是我们还是明确一下细节。因为我是区。

首先线段树维护的是 \(f_i\),并且需要注意下标范围,操作是“区间加”和“查询区间最大值”。\(g_i\) 也搞定了。

注意到 \(v_p\) 按照类时间顺序出现。这和 dp 的转移有联系:\(i\) 大的就能选更多的 \(v_p\) 咯。所以可以用一个指针来存当前处理到哪一个挑战。这样 \(\sum v_p\) 就可以计算了。具体操作是:每处理到一个挑战,把它加入线段树。

还需要一点点卡常,非递归函数使用 inline 即可。

AC Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=1e5+5,inf=1e18;
int n,m,k,d,t[M<<3],tag[M<<3],bz[M<<1],len;
struct node{
	int l,r,v;
}a[M];
bool c1(const node& s1,const node& s2){
	return s1.r<s2.r;
}
inline int lc(int x){return x<<1;}
inline int rc(int x){return x<<1|1;}
inline void pushup(int p){
	t[p]=max(t[lc(p)],t[rc(p)]);
}
void build(int p,int l,int r){
	if(l==r)	return t[p]=0,void();
	int mid=l+r>>1;
	build(lc(p),l,mid);build(rc(p),mid+1,r);
	pushup(p);
}
inline void pushdown(int p){
	if(tag[p]){
		int T=tag[p];
		tag[lc(p)]+=T;
		tag[rc(p)]+=T;
		t[lc(p)]+=T;
		t[rc(p)]+=T;
		tag[p]=0;
	}
}
void update(int p,int l,int r,int L,int R,int d){
	if(L<=l&&r<=R){
		tag[p]+=d;t[p]+=d;
		return ;
	}
	pushdown(p);
	int mid=l+r>>1;
	if(L<=mid)	update(lc(p),l,mid,L,R,d);
	if(R>mid)	update(rc(p),mid+1,r,L,R,d);
	pushup(p);
}
int query(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)	return t[p];
	pushdown(p);
	int mid=l+r>>1,res=-inf;
	if(L<=mid)	res=max(res,query(lc(p),l,mid,L,R));
	if(R>mid)	res=max(res,query(rc(p),mid+1,r,L,R));
	return res;
}
void solve(){
	cin>>n>>m>>k>>d;
	len=0;
	memset(tag,0,sizeof(tag));
	for(int i=1,x,ln,v;i<=m;i++){
		cin>>x>>ln>>v;
		a[i]={x-ln,x,v};
		bz[++len]=a[i].l;bz[++len]=a[i].r;
	}
	sort(bz+1,bz+len+1);
	len=unique(bz+1,bz+len+1)-bz-1;
	for(int i=1;i<=m;i++){
		a[i].l=lower_bound(bz+1,bz+len+1,a[i].l)-bz;
		a[i].r=lower_bound(bz+1,bz+len+1,a[i].r)-bz;
	}
	sort(a+1,a+m+1,c1);
	build(1,0,len-1);//第 0 天的转移 
	int pos=1,ans=0;
	for(int i=1;i<=len;i++){
		update(1,0,len-1,0,i-1,-d*(bz[i]-bz[i-1]));
		while(pos<=m&&a[pos].r==i){
			update(1,0,len-1,0,a[pos].l,a[pos].v);
			pos++;
		}
		int ll=lower_bound(bz+1,bz+len+1,bz[i]-k)-bz;
		ans=max(ans,query(1,0,len-1,ll,i-1));
		if(i+1<len)	update(1,0,len-1,i+1,i+1,ans);
	}
	cout<<ans<<"\n";
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	int c,T;cin>>c>>T;
	while(T--)	solve();
	return 0;
}
posted @ 2026-10-23 20:00  深申  阅读(5)  评论(0)    收藏  举报