D - Portals

参考:CF1271D Portals dp 贪心

主要要明白两点:

如果a和b都能够派兵前去把守c,且a>b,那么从a派兵去把守c是更优解

派兵要派往分数最大的地方,要把有限的派兵机会用在最值的地方

要实现这两步,要学会反悔贪心法,即如果当前兵力不足以攻打下一个城池,那么我们可以对之前派出去的兵进行“反悔”,即不派出军队,而在这个时候我们应该依次从分值小到分值大的城池进行反悔(可用一个优先队列进行维护),这样得到的结果才是最优的。

代码:

// Created by CAD on 2020/1/7.
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=5005;
int last[maxn],a[maxn],b[maxn],c[maxn];
priority_queue<int> value[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;++i)
        cin>>a[i]>>b[i]>>c[i],last[i]=i;
    for(int i=1,u,v;i<=m;++i)
        cin>>u>>v,last[v]=max(last[v],u);
    for(int i=1;i<=n;++i)
        value[last[i]].push(c[i]);
    priority_queue<int,vector<int>,greater<int> > q;
    ll sum=k;
    for(int i=1;i<=n+1;++i)         //边界为n+1的原因是要保证sum的值非负,且要得到最优值      
    {
        while((!q.empty())&&sum<a[i])
            sum++,q.pop();
        if(sum<a[i])
            return puts("-1");
        sum+=b[i];
        while(!value[i].empty())
            sum--,q.push(value[i].top()),value[i].pop();
    }
    ll ans=0;
    while(!q.empty())
        ans+=q.top(),q.pop();
    cout<<ans<<endl;
    return 0;
}

几个毒瘤数据:

Input

3 2 1
0 0 20
0 0 10
0 0 5
2 1
3 1

Answer

20

Input

1 0 0
0 0 5

Answer

0