Codeforces - 1106E - Lunar New Year and Red Envelopes 优先队列+dp

题目链接

题意:现在有 k k 个红包,总共 n n 的时间, B o b Bob 采用贪心策略,每个时间点若有红包能取则取钱数 w i w_i 最多的,且取完之后直到 d i d_i 个时间点之后才能再取红包, A l i c e Alice m m 次机会在一个时间点让 B o b Bob 不能做任何操作, A l i c e Alice 怎么分配这 m m 次机会才能使得 B o b Bob 获得的钱数最少,问最少的钱数为多少。

思路:很明显是 d p dp ,状态为第 i i 个时间点, A l i c e Alice 用了 j j 次机会。对于每个点 B o b Bob 要选择的红包,可以通过优先队列每次更新。由于 t i d i t_i \leq d_i 所以对于一个时间点若选取第 i i 个红包,则影响的状态的时间点优先队列里已经不存在第 i i 个红包,所以直接 d p dp 即可。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <cmath>
using namespace std;
#define ll long long
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 100005
#define debug true
#define lowbit(x) ((-x)&x)
#define ffor(i,d,u) for(int i=(d);i<=(u);++i)
#define _ffor(i,u,d) for(int i=(u);i>=(d);--i)
#define mst(array,Num,Kind,Count) memset(array,Num,sizeof(Kind)*(Count))
int n, m, k;
struct node
{
    int s, t, d;
    long long w;
    bool operator<(const node &x)const
    {
        if (w != x.w)
            return w < x.w;
        return d < x.d;
    }
}r[NUM];
long long dp[NUM][205];
priority_queue<node, vector<node>, less<node> > p;
template <typename T>
inline void read(T &x){
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
template <typename T>
inline void write(T x)
{
    int len=0;char c[21];
    if(x<0)putchar('-'),x*=(-1);
    do{++len;c[len]=(x%10)+'0';}while(x/=10);
    _ffor(i,len,1)putchar(c[i]);
}
inline bool cmp(const node &x, const node &y)
{
    return x.s < y.s;
}
inline void AC()
{
    int h = 1;
    node x;
    dp[0][0] = 0;
    read(n), read(m), read(k);
    ffor(i, 1, k) read(r[i].s), read(r[i].t), read(r[i].d), read(r[i].w);
    ffor(i, 1, n)
        ffor(j, 0, min(i, m))
            dp[i][j] = 100000000000005;
    sort(r + 1, r + 1 + k, cmp);
    ffor(i, 0, n)
    {
        while (h <= k && r[h].s <= i + 1)//压入可以选择的红包
        {
            p.push(r[h]);
            ++h;
        }
        if (!p.empty())//弹出已经超过时间点的红包
        {
            x = p.top();
            while (x.t < i + 1)
            {
                p.pop();
                if (p.empty())
                    break;
                x = p.top();
            }
        }
        ffor(j, 0, min(i, m))
            if(p.empty())//当前时间点没有红包可以选择
                dp[i + 1][j] = min(dp[i + 1][j], dp[i][j]);
            else
            {
                dp[x.d][j] = min(dp[i][j] + x.w, dp[x.d][j]);//Bob选择红包
                dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j]);//Alice使用一次机会
            }
    }
    long long ans = dp[n][0];
    ffor(i, 1, min(n, m)) ans = min(ans, dp[n][i]);
    write(ans);
}
int main()
{
    AC();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a302549450/article/details/86755032