Codeforces Contest 1106 problem E Lunar New Year and Red Envelopes —— dp+优先队列

202 篇文章 5 订阅

Lunar New Year is approaching, and Bob is going to receive some red envelopes with countless money! But collecting money from red envelopes is a time-consuming process itself.

Let’s describe this problem in a mathematical way. Consider a timeline from time 1 to n. The i-th red envelope will be available from time si to ti, inclusive, and contain wi coins. If Bob chooses to collect the coins in the i-th red envelope, he can do it only in an integer point of time between si and ti, inclusive, and he can’t collect any more envelopes until time di (inclusive) after that. Here si≤ti≤di holds.

Bob is a greedy man, he collects coins greedily — whenever he can collect coins at some integer time x, he collects the available red envelope with the maximum number of coins. If there are multiple envelopes with the same maximum number of coins, Bob would choose the one whose parameter d is the largest. If there are still multiple choices, Bob will choose one from them randomly.

However, Alice — his daughter — doesn’t want her father to get too many coins. She could disturb Bob at no more than m integer time moments. If Alice decides to disturb Bob at time x, he could not do anything at time x and resumes his usual strategy at the time x+1 (inclusive), which may lead to missing some red envelopes.

Calculate the minimum number of coins Bob would get if Alice disturbs him optimally.

Input
The first line contains three non-negative integers n, m and k (1≤n≤105, 0≤m≤200, 1≤k≤105), denoting the length of the timeline, the number of times Alice can disturb Bob and the total number of red envelopes, respectively.

The following k lines describe those k red envelopes. The i-th line contains four positive integers si, ti, di and wi (1≤si≤ti≤di≤n, 1≤wi≤109) — the time segment when the i-th envelope is available, the time moment Bob can continue collecting after collecting the i-th envelope, and the number of coins in this envelope, respectively.

Output
Output one integer — the minimum number of coins Bob would get if Alice disturbs him optimally.

Examples
inputCopy
5 0 2
1 3 4 5
2 5 5 8
outputCopy
13
inputCopy
10 1 6
1 1 2 4
2 2 6 2
3 3 3 3
4 4 4 5
5 5 5 7
6 6 6 9
outputCopy
2
inputCopy
12 2 6
1 5 5 4
4 6 6 2
3 8 8 3
2 9 9 5
6 10 10 7
8 12 12 9
outputCopy
11
Note
In the first sample, Alice has no chance to disturb Bob. Therefore Bob will collect the coins in the red envelopes at time 1 and 5, collecting 13 coins in total.

In the second sample, Alice should disturb Bob at time 1. Therefore Bob skips the first envelope, collects the second one and can not do anything after that. So the answer is 2.

题意:

给你长度为n的时间线,女儿可以捣乱的时间长度,红包的个数,接下来是k个红包可以领取的起始时间,终止时间,和领取这个红包之后他至少要等到di+1的时间才能领取下一个红包的di,和这个红包里面有多少钱。如果能领红包他会领金额最大的,多个会领di最大的。在女儿捣乱的时候不能领红包,问你这个人最后最少能领到多少钱。

题解:

优先队列存放当前的红包,dp[i][j]表示在第i个时间点,女儿捣乱j分钟最少能领多少钱,那么有两种情况:现在没有红包领,那么这个状态就要继承到下一个状态,注意不是从上一个继承下来,因为在i的时候是有红包的,在i+1的时候才没有,所以这种情况的状态转移方程是dp[i+1][j]=min(dp[i+1][j],dp[i][j])(我一开始一直没想清楚这块,所以怎么都过不去,卡在第7个),还有一种就是现在有红包的时候,但是如果没有这个状态,就是说在第i个时间女儿吵闹j次是不可能的,那么就continue,否则就有两种情况:这时候女儿吵闹,或者领了当前最优的红包:
dp[i+1][j+1]=min(dp[i][j],dp[i+1][j+1]);
dp[now.d+1][j]=min(dp[now.d+1][j],dp[i][j]+now.w);
最后因为是将状态转移到di+1这里,所以n也要转移到n+1这里,前提是n+1没有状态。
(太坑啦,打注释的地方真的就是想不到一直卡住)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
const ll inf=1e18;
ll dp[N][205];
struct node
{
    int sta,fin,d;
    ll w;
    bool operator< (const node& a)const
    {
        if(w!=a.w)
            return w<a.w;
        return d<a.d;
    }
}p[N];
bool cmp(node a,node b)
{
    return a.sta<b.sta;
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++)
        scanf("%d%d%d%lld",&p[i].sta,&p[i].fin,&p[i].d,&p[i].w);
    sort(p+1,p+1+k,cmp);
    for(int i=1;i<=n+1;i++)
        for(int j=0;j<=m;j++)
            dp[i][j]=inf;
    dp[p[1].sta][0]=0;
    int pos=1;
    priority_queue<node>Q;
    node now;
    int flag;
    for(int i=p[1].sta;i<=n;i++)
    {
        while(p[pos].sta==i)
            Q.push(p[pos++]);
        while(!Q.empty()&&Q.top().fin<i)
            Q.pop();
        flag=0;
        if(Q.empty())
            flag=1;
        else
            now=Q.top();
        for(int j=0;j<=m;j++)
        {
            if(!flag&&dp[i][j]==inf)
                continue;

            if(flag)
                dp[i+1][j]=min(dp[i][j],dp[i+1][j]);//不能是dp[i-1][j]因为i-1这个状态队列里是有东西的,所以要从这个状态开始向下
            else
            {
                dp[i+1][j+1]=min(dp[i][j],dp[i+1][j+1]);
                dp[now.d+1][j]=min(dp[now.d+1][j],dp[i][j]+now.w);
            }
        }
    }
    for(int i=0;i<=m;i++)
    {
        if(dp[n+1][i]!=inf)
            continue;
        else
            dp[n+1][i]=dp[n][i];
    }
    ll minn=inf;
    for(int i=0;i<=m;i++)
        minn=min(minn,dp[n+1][i]);
    printf("%lld\n",minn);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值