Codeforces Round #536 (Div. 2) E dp + set

https://codeforces.com/contest/1106/problem/E

题意

一共有k个红包,每个红包在\([s_i,t_i]\)时间可以领取,假如领取了第i个红包,那么在\(d_i\)后才能领取下一个红包,每个红包价值\(w_i\),对方假如有机会领取红包他一定会领取,你有m次阻止对方领取的机会,问对方最少可以拿到多少红包

题解

  • 定义dp[i][j]为前i秒用了j次机会让对方拿到最小价值的红包
  • \(dp[i][j] - > dp[i+1][j+1]\) 假如使用阻止
  • \(dp[i][j] - > dp[d[s]+1][j]\) 假如不用
  • \(dp[i][j] - > dp[i+1][j]\) 这一秒没有可以领的红包
  • 用set处理当前第i秒可以领的优先级最高的红包

代码

#include<bits/stdc++.h>
#define pii pair<int,int>
#define MAXN 100005
#define mk make_pair
#define inf 0x3f3f3f3f
#define ll long long 
#define ft first
#define se second
using namespace std;
vector<pii>in[MAXN],out[MAXN];
multiset<pii>S;
int n,m,k,i,j,s,t,d,w;
ll dp[MAXN][205];
int main(){
    cin>>n>>m>>k;
    for(i=0;i<k;i++){
        scanf("%d%d%d%d",&s,&t,&d,&w);
        in[s].push_back(mk(w,d));
        out[t+1].push_back(mk(w,d));
    }
    memset(dp,inf,sizeof(dp));
    for(i=0;i<=m;i++)dp[1][i]=0;
    for(i=0;i<=n;i++){
        for(auto x:in[i])S.insert(x);
        for(auto x:out[i])S.erase(S.find(x));
        for(j=0;j<=m;j++){
            auto p=S.begin();
            if(p==S.end())
            dp[i+1][j]=min(dp[i+1][j],dp[i][j]);
            else{
            p=S.end();p--;
            dp[p->se+1][j]=min(dp[i][j]+p->ft,dp[p->se+1][j]);
            dp[i+1][j+1]=min(dp[i][j],dp[i+1][j+1]);
            }
        }
    }
    cout<<dp[n+1][m];
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10628982.html