线段树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的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces675 E. Trains and Statistic(dp,线段树)
Codeforces Round #721 (Div. 2) E. Partition Game 线段树优化DP