【题解】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;
}
posted @ 2025-07-16 10:11  Lucyna_Kushinada  阅读(68)  评论(0)    收藏  举报