Codeforces 1106 E. Lunar New Year and Red Envelopes 优先队列+dp
题意大致是Bob新年拿红包,每个红包可以在s-t时间内取,但是取了之后得在d+1时间开始才能继续取红包。
同时他女儿能在m个时间点阻止他取红包,求女儿阻止后Bob取得的w总和最小值。
Bob取红包的策略是固定的,有红包就一定取,有多个就取w最大的,仍然有多个就取d最大的。
这个题意读了半天,不得不感叹Bob他孩子真是亲生的,都是傻子ww。
这个题首先第一感觉就是个典型的dp,但是想了想觉得女儿的阻止操作会影响后续当时状态的红包状态,纠结了半天。
但是其实我们可以发现,首先Bob的操作本来应该是固定的,每个时间红包状态显然也是固定的。
Bob的女儿的影响其实是不会改变每个时间取的红包,取了红包后转移到d+1时刻,而被阻止了取红包是转移到now+1时刻。
所以说,我们只要在每个时刻用优先队列得到当时根据Bob策略要取的红包,直接进行转移即可。
#include<bits/stdc++.h> using namespace std; int i,i0,n,m,k; long long dp[100005][205]; struct node { int s,t,d,w; }a[100005]; bool cmp(node a,node b){return a.s<b.s;} struct cmp0{ bool operator()(node a,node b) { if(a.w==b.w)return a.d<b.d; return a.w<b.w;} }; priority_queue<node,vector<node>,cmp0>q; int main() { scanf("%d %d %d",&n,&m,&k); for(i=1;i<=k;i++)scanf("%d %d %d %d",&a[i].s,&a[i].t,&a[i].d,&a[i].w); sort(a+1,a+1+k,cmp); for(i=2;i<=n+1;i++)for(i0=0;i0<=m;i0++)dp[i][i0]=(long long)INT_MAX*INT_MAX/2; for(i=1,i0=1;i<=n;i++) { while(i0<=k&&a[i0].s==i)q.push(a[i0++]); while(!q.empty()&&q.top().t<i)q.pop(); if(q.empty()) { for(int i1=0;i1<=m;i1++)dp[i+1][i1]=min(dp[i+1][i1],dp[i][i1]); } else { for(int i1=0;i1<=m;i1++)dp[q.top().d+1][i1]=min(dp[q.top().d+1][i1],dp[i][i1]+q.top().w); for(int i1=0;i1<m;i1++)dp[i+1][i1+1]=min(dp[i+1][i1+1],dp[i][i1]); } } long long ans=(long long)INT_MAX*INT_MAX/2; for(i=0;i<=m;i++)ans=min(ans,dp[n+1][i]); printf("%lld\n",ans); return 0; }