题意:现在有 k k k 个红包,总共 n n n 的时间, B o b Bob Bob 采用贪心策略,每个时间点若有红包能取则取钱数 w i w_i wi 最多的,且取完之后直到 d i d_i di 个时间点之后才能再取红包, A l i c e Alice Alice 有 m m m 次机会在一个时间点让 B o b Bob Bob 不能做任何操作, A l i c e Alice Alice 怎么分配这 m m m 次机会才能使得 B o b Bob Bob 获得的钱数最少,问最少的钱数为多少。
思路:很明显是 d p dp dp,状态为第 i i i 个时间点, A l i c e Alice Alice 用了 j j j 次机会。对于每个点 B o b Bob Bob 要选择的红包,可以通过优先队列每次更新。由于 t i ≤ d i t_i \leq d_i ti≤di 所以对于一个时间点若选取第 i i i 个红包,则影响的状态的时间点优先队列里已经不存在第 i i i 个红包,所以直接 d p dp 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;
}