线段树or优先队列+dp E. Lunar New Year and Red Envelopes

Posted echozqn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树or优先队列+dp E. Lunar New Year and Red Envelopes相关的知识,希望对你有一定的参考价值。

线段树or优先队列+dp E. Lunar New Year and Red Envelopes

题目大意:

技术图片

题解:

(dp[i][j]) 表示到时间 (i) 打扰了 (j) 次获得的最少的硬币数量

因为如果这个时间点有东西拿,那么必须按照策略拿,先预处理每一个时间点如果要拿的东西,然后写转移方程,这个转移有三种情况:

  • (dp[d[x]+1][j]=min(dp[d[x]+1][j],dp[i][j]))
  • 不拿,被打扰了 (dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]))
  • 如果没东西拿 (dp[i+1][j]=min(dp[i+1][j],dp[i][j]))

预处理这个时间点要拿的东西,可以用线段树,也可以用优先队列。

线段树就是一个区间更新,优先队列按照 (s) 排序放进去,然后队列里面第一关键词是w,然后是d,每次拿一个出来,如果当前时间点已经大于 (t) 了,那就删掉继续拿,一直到符合条件,或者队列为空。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5+10;
typedef long long ll;
int num[maxn<<2],lazy[maxn<<2];
int lc[maxn],rc[maxn],d[maxn],w[maxn];

int Max(int x,int y){
    if((w[x]>w[y])||(w[x]==w[y]&&d[x]>d[y])) return x;
    return y;
}
void push_up(int id){
    num[id]=Max(num[id<<1],num[id<<1|1]);
}

void push_down(int id){
	if(!lazy[id]) return ;
    num[id<<1]=Max(lazy[id],num[id<<1]);
    num[id<<1|1]=Max(lazy[id],num[id<<1|1]);
    lazy[id<<1]=Max(lazy[id<<1],lazy[id]);
    lazy[id<<1|1]=Max(lazy[id<<1|1],lazy[id]);
    lazy[id]=0;
}
void update(int id,int l,int r,int x,int y,int val){
    if(x<=l&&y>=r){
        num[id]=Max(num[id],val);
        lazy[id]=Max(lazy[id],val);
        return ;
    }
    push_down(id);
    int mid=(l+r)>>1;
    if(x<=mid) update(id<<1,l,mid,x,y,val);
    if(y>mid) update(id<<1|1,mid+1,r,x,y,val);
    push_up(id);
}
int query(int id,int l,int r,int pos){
    if(l==r) return num[id];
    push_down(id);
    int mid=(l+r)>>1;
    if(pos<=mid) return query(id<<1,l,mid,pos);
    return query(id<<1|1,mid+1,r,pos);
}

ll dp[maxn][220];
int main(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++){
        scanf("%d%d%d%d",&lc[i],&rc[i],&d[i],&w[i]);
        update(1,1,n,lc[i],rc[i],i);
    }
    memset(dp,inf64,sizeof(dp));
    dp[1][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(dp[i][j]>=inf64) continue;
            int x = query(1,1,n,i);
//            printf("i=%d j=%d x=%d
",i,j,x);
            if(!x) dp[i+1][j]=min(dp[i+1][j],dp[i][j]);
            else{
                if(j+1<=m) dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]);
                dp[d[x]+1][j]=min(dp[d[x]+1][j],dp[i][j]+w[x]);
//                printf("dp[%d][%d]")
            }
        }
    }
    ll ans = inf64;
    for(int i=0;i<=m;i++) ans = min(ans,dp[n+1][i]);
    printf("%lld
",ans);
    return 0;
}


以上是关于线段树or优先队列+dp E. Lunar New Year and Red Envelopes的主要内容,如果未能解决你的问题,请参考以下文章

牛客小白月初赛-卷王之王(优先队列or线段树)

Codeforces675 E. Trains and Statistic(dp,线段树)

DP线段树优化琪露诺

Codeforces Round #721 (Div. 2) E. Partition Game 线段树优化DP

Atcoder arc080E Young Maids(线段树+优先队列)

HDU 5700 优先队列(或者multiset) 或 线段树