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;
}

猜你喜欢

转载自www.cnblogs.com/megalovania/p/10455070.html