题面链接:https://codeforces.com/contest/1106/problem/E
难度:2100
题意:现在有长度为N的时间线 A现在要领红包 有K个红包 每个红包 四个属性 这个红包只在[s,t]的时间区间内出现,并且领了这个红包后在D的时间前不能领红包了(包括D时间)这个红包价值W。他在每个时间上领W最大的红包,若果W相同领D大的。现在B可以打断A领红包M次。打断的意思是在某一个时间让他不能领红包。M最大为200。问B能采取什么策略让A能领的W合最小
思路:这题思路很简单 就是选取至多M个时间点打断他 让他的红包钱最少。
很清楚这个dp有两个转移 :每次他能领红包的时候 可以打断 直接转移到 D+1
要不就是打断他 让他转移到 i+1
dp[i][j] 表示在i的时间线之前打断j次A能拿到最少的钱为多少
注意 当他在i这个时间点 没红包选时 只能直接转到下一个i
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
ll t,d,w;
operator < (const node &n1)const{
if(w==n1.w) return d<n1.d;
return w<n1.w;
}
}arr[100050];
vector<int> pos[100005];
long long dp[100050][205];
int main()
{
int n,m,k;
cin>>n>>m>>k;
priority_queue <node> q1;
for(int i=0;i<k;i++){
ll s;
scanf("%lld%lld%lld%lld",&s,&arr[i].t,&arr[i].d,&arr[i].w);
pos[s].push_back(i);
}
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m;j++){
dp[i][j] = 1<<30;
dp[i][j] *= 1<<30;
}
}
for(int i=0;i<=m;i++){
dp[1][i] = 0;
}
for(int i=1;i<=n;i++){
for(auto tmp : pos[i]){
q1.push(arr[tmp]);
}
ll d=-1,w=-1;
while(!q1.empty()){
node tmp = q1.top();
q1.pop();
int t = tmp.t;
if(t<i) continue;
d = tmp.d;
w = tmp.w;
q1.push(tmp);
break;
}
d++;
for(int j=0;j<=m;j++){
if(!d){
dp[i+1][j] = min(dp[i+1][j],dp[i][j]);
continue;
}
dp[d][j] = min(dp[i][j] + w,dp[d][j]);
dp[i+1][j+1] = min(dp[i+1][j+1] , dp[i][j]);
}
}
ll ans = 1<<30;
ans *= ans;
for(int i=0;i<=m;i++){
ans = min(ans,dp[n+1][i]);
}
cout<<ans;
return 0;
}