【题解】P9871 [NOIP2023] 天天爱打卡
P9871 [NOIP2023] 天天爱打卡
题意
有 \(n\) 天,每天可以选择打卡或者不打卡,如果进行打卡,则会使能量会减少 \(d\)。
有 \(m\) 个激励任务,第 \(i\) 个为如果在第 \(x_i-y_i+1\sim y_i\) 天每天都进行打卡,则会使能力增加 \(v_i\)。
另外,不能连续打卡超过 \(k\) 天。
请求出第 \(n\) 天后,能量可能的最大值。
题解
知识点:动态规划,线段树,离散化。
两年前的疑难杂症,今天来解决。
先同时执行 \(x_i\leftarrow x_i-y_i+1\),\(y_i\leftarrow x_i\),转化为区间形式。
设 \(dp_i\) 为处理到第 \(i\) 天且当天不一定打卡的最大能量。
初始 \(dp_i=dp_{i-1}\)。
也可以枚举打卡连续段 \(\displaystyle dp_i=\max_{j=i-k+1}^{i} dp_{j-2}+w(j,i)-(i-j+1)d\),其中 \(w(i,j)\) 表示被 \([i,j]\) 包含的任务的 \(v_i\) 之和。
对于 \(w(i,j)\) 的处理,可以考虑扫描线,扫到端点 \(y_i\) 再加入,这样只需要查询 \(x_i\ge j\) 的 \(v_i\) 之和。
值域是 \(10^9\) 的,先离散化。
然后直接上线段树优化 dp 就行了,上面的式子很好拆。
需要注意的是离散化也要把 \(x_i-2\) 放进去,因为这个调了一会,纯坑啊。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 302506
#define int long long
int n,m,k,d,len,dp[N];
int x[N],y[N],v[N];
vector<int>tmp;
vector<pr>ad[N];
struct segt{
#define mid ((l+r)>>1)
int ad[N<<2],tg[N<<2],tr[N<<2],ans[N<<2];
inline void addt(int k,int d){
ad[k]+=d;
tg[k]+=d;
ans[k]+=d;
}
inline void pd(int k){
if(tg[k]){
addt(k*2,tg[k]);
addt(k*2+1,tg[k]);
tg[k]=0;
}
}
inline void un(int k){
// ad[k]=max(ad[k*2],ad[k*2+1]);
// tr[k]=max(tr[k*2],tr[k*2+1]);
ans[k]=max(ans[k*2],ans[k*2+1]);
}
inline void build(int k,int l,int r){
ad[k]=tr[k]=tg[k]=ans[k]=0;
if(l==r){
return;
}
build(k*2,l,mid);
build(k*2+1,mid+1,r);
un(k);
}
inline void edit(int L,int k,int l,int r,int d){
if(l==r){
tr[k]=max(tr[k],d);
ans[k]=tr[k]+ad[k];
return;
}
pd(k);
if(L<=mid){
edit(L,k*2,l,mid,d);
}
else{
edit(L,k*2+1,mid+1,r,d);
}
un(k);
}
inline void add(int L,int R,int k,int l,int r,int d){
if(L<=l&&R>=r){
addt(k,d);
return;
}
pd(k);
if(L<=mid){
add(L,R,k*2,l,mid,d);
}
if(R>mid){
add(L,R,k*2+1,mid+1,r,d);
}
un(k);
}
inline int ask(int L,int R,int k,int l,int r){
if(L<=l&&R>=r){
return ans[k];
}
pd(k);
int res=0;
if(L<=mid){
res=ask(L,R,k*2,l,mid);
}
if(R>mid){
res=max(res,ask(L,R,k*2+1,mid+1,r));
}
return res;
}
#undef mid
}t;
inline void sol(){
tmp.clear();
cin>>n>>m>>k>>d;
rep(i,1,m){
cin>>x[i]>>y[i]>>v[i];
int l=x[i]-y[i]+1,r=x[i];
x[i]=l+1;
y[i]=r+1;
tmp.pb(x[i]);
tmp.pb(y[i]);
tmp.pb(x[i]-2);
// tmp.pb(y[i]-2);
}
tmp.pb(0);
sort(all(tmp));
tmp.erase(unique(all(tmp)),ed(tmp));
len=sz(tmp)-1;
rep(i,0,len){
dp[i]=0;
ad[i].clear();
}
t.build(1,0,len);
rep(i,1,m){
x[i]=lower_bound(all(tmp),x[i])-bg(tmp);
y[i]=lower_bound(all(tmp),y[i])-bg(tmp);
ad[y[i]].pb({x[i],v[i]});
}
rep(i,0,len){
for(pr u:ad[i]){
t.add(0,u.fi,1,0,len,u.se);
// cout<<i<<" : addln "<<0<<' '<<u.fi<<"\n";
}
int l=lower_bound(all(tmp),tmp[i]-k+1)-bg(tmp);
// cout<<"sbrt "<<t.ans[1]<<"\n";
// cout<<i<<" qry : "<<l<<' '<<i<<' '<<t.ask(l,i,1,0,len)<<"\n";
if(i){
dp[i]=dp[i-1];
}
dp[i]=max(dp[i],t.ask(l,i,1,0,len)-(tmp[i]+1)*d);
int pos=lower_bound(all(tmp),tmp[i]+2)-bg(tmp);
// cout<<i<<" pos : "<<pos<<' '<<dp[i]+tmp[pos]*d<<"\n";
t.edit(pos,1,0,len,dp[i]+tmp[pos]*d);
}
// rep(i,0,len){
// cout<<dp[i]<<" ";
// }
cout<<*max_element(dp,dp+1+len)<<"\n";
}
signed main(){
// freopen("run.in","r",stdin);
// freopen("run.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int c,t;
cin>>c>>t;
rep(i,1,t){
sol();
}
return 0;
}

浙公网安备 33010602011771号