码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-07-29 14:52:00      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:技术   its   namespace   队列   red   env   lun   ORC   就是   

线段树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\n",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\n",ans);
    return 0;
}


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

标签:技术   its   namespace   队列   red   env   lun   ORC   就是   

原文地址:https://www.cnblogs.com/EchoZQN/p/13396081.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!