[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;
}
古顾故

浙公网安备 33010602011771号