题目链接:https://codeforces.com/contest/1106/problem/E
题目大意:一共有n时间,有k个红包,每个红包能在si~ti时间内出现,里面有wi的钱,取完后要到di后才能继续取红包,有个人可以m次阻挠,问最后能拿到最少的钱是多少。
题目思路:采用dp,一个时间点有三种情况,没红包可拿,拿了红包,跳了红包。所以设置dp[i][j],i表示前is用j次阻挠机会的最小值。所以三种情况分别是,没红包可拿:dp[i+1][j]=dp[i][j],直接继承。遇到了红包的话,如果拿了红包,那就更新di+1的结果,如果跳了红包,那就更新dp[i+1][j+1]
以下是代码:
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 1e5+5;
const int MOD = 1e9+7;
ll dp[MAXN][205];
int n,m,k;
struct node{
int s,t,d,w;
bool operator <(const node &x)const{
if(x.w==w)return x.d>d;
return x.w>w;
}
}a[MAXN];
bool cmp(node a,node b){
return a.s<b.s;
}
priority_queue<node>q;
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
rep(i,1,k){
scanf("%d%d%d%d",&a[i].s,&a[i].t,&a[i].d,&a[i].w);
}
sort(a+1,a+k+1,cmp);
while(!q.empty())q.pop();
memset(dp,0x3f,sizeof(dp));
dp[1][0]=0;
int num=1;
ll ans=1ll<<62;
rep(i,1,n){
while(num<=k&&a[num].s<=i)q.push(a[num++]);
while(!q.empty()&&q.top().t<i)q.pop();
if(q.empty()){
rep(j,0,m){
dp[i+1][j]=min(dp[i][j],dp[i+1][j]);
}
}
else{
rep(j,0,m){
node temp=q.top();
dp[temp.d+1][j]=min(dp[temp.d+1][j],dp[i][j]+temp.w);
if(j<m){
dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]);
}
}
}
}
rep(i,0,m){
ans=min(ans,dp[n+1][i]);
}
cout<<ans<<endl;
}
return 0;
}