Codeforces - 1106E - Lunar New Year and Red Envelopes 優先隊列+dp

題目鏈接

題意:現在有 kk 個紅包,總共 nn 的時間, BobBob 採用貪心策略,每個時間點若有紅包能取則取錢數 wiw_i 最多的,且取完之後直到 did_i 個時間點之後才能再取紅包, AliceAlicemm 次機會在一個時間點讓 BobBob 不能做任何操作,AliceAlice 怎麼分配這 mm 次機會才能使得 BobBob 獲得的錢數最少,問最少的錢數爲多少。

思路:很明顯是 dpdp,狀態爲第 ii 個時間點, AliceAlice 用了 jj 次機會。對於每個點 BobBob 要選擇的紅包,可以通過優先隊列每次更新。由於 tidit_i \leq d_i 所以對於一個時間點若選取第 ii 個紅包,則影響的狀態的時間點優先隊列裏已經不存在第 ii 個紅包,所以直接 dpdp 即可。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章