比赛时看到这题懵逼了,比完赛仔细一想是个很简单的dp = =
由于题目限制,可以发现\(B\)取红包的策略是唯一的,可以用优先队列预处理出\(B\)在第\(i\)秒可以拿到的红包的收益\(w_i\)和如果拿了红包后下次拿红包的最早时间\(t_i\)(防止重复计算)
设\(f[i][j]\)表示\(A\)在第\(i\)秒打扰\(B\) \(j\)次所能获得的最小收益
于是有以下方程:
\[f[i+1][j+1]=f[i][j]\]
\[f[t_i][j]=f[t_i][j]+w_i\]
代码:
#include <bits/stdc++.h>
#define N 100010
using namespace std;
struct qwq{
int s,t,d,w;
}a[N];
int W[N],T[N],n,k,m;
long long f[N][210];
bool cmp(const qwq &x,const qwq &y){ return (x.s==y.s)?x.t<y.t:x.s<y.s; }
bool operator <(qwq x,qwq y){
return (x.w==y.w)?x.d<y.d:x.w<y.w;
}
priority_queue<qwq>q;
void init(){
int cnt=1,stop=0,tmp1=0,tmp2=0;qwq x;
for(int i=1;i<=n;++i){
while(cnt<=k && a[cnt].s<=i) q.push(a[cnt++]);
while(!q.empty() && q.top().t<i) q.pop();
if(!q.empty()){
x=q.top();
T[i]=x.d+1,W[i]=x.w;
}
}
}
int main(){
int i,j;
long long ans;
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+k+1,cmp);
init();
memset(f,0x3f,sizeof(f));
T[0]=1;ans=f[0][0],f[0][0]=0;
for(i=0;i<=n;++i){
for(j=0;j<=m;++j){
f[i+1][j+1]=min(f[i][j],f[i+1][j+1]);
if(T[i]) f[T[i]][j]=min(f[i][j]+W[i],f[T[i]][j]);
else f[i+1][j]=min(f[i][j],f[i+1][j]);
}
}
for(i=0;i<=m;++i) ans=min(ans,f[n+1][i]);
cout<<ans;
}