D. Portals
由于每个点可以选择前面的某些点存在重复选择的情况,考虑除去重复选择的可能。
贪心:对于每一个城堡,我们都尽可能在最晚的时间控制,也就是在最后一个能控制它的点考虑是否控制。
于是考虑设计dp
状态表示:f(i,j)f_{(i,j)}f(i,j)表示考虑到第iii个城堡(已经占领),当前士兵是jjj的情况的最大值
状态转移:①不选择占领城堡从第i−1i-1i−1个城堡转移②考虑占领城堡
注意:考虑第iii个城堡占领的情况时,可以占领多个城堡因而与“分组背包”不同(分组背包每组只能选一个)
#define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#pragma GCC optimize(2)
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int N=5010;
int a[N],b[N],c[N];
int n,m,k;
int f[N][N];
int last[N];
vector<int> g[N];
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n>>m>>k;for(int i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i];while(m--){int u,v;cin>>u>>v;last[v]=max(last[v],u);}for(int i=1;i<=n;i++){last[i]=max(last[i],i);g[last[i]].push_back(i);}memset(f,-0x3f,sizeof f);f[0][k]=0;for(int i=1;i<=n;i++){for(int j=a[i];j+b[i]<=5000;j++)f[i][j+b[i]]=max(f[i][j+b[i]],f[i-1][j]);for(auto t:g[i])for(int j=0;j<=4999;j++)f[i][j]=max(f[i][j],f[i][j+1]+c[t]);}int res=-1;for(int i=0;i<=5000;i++) res=max(res,f[n][i]);cout<<res<<'\n';}return 0;
}
带悔贪心
nlog(n)n\log(n)nlog(n)
用一个优先队列维护选择的集合,每次把每个城堡连接的城堡都占领,士兵不够的时候从优先队列集合中弹出
#define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#pragma GCC optimize(2)
#include<queue>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int N=5010;
int a[N],b[N],c[N];
int n,m,k;
int last[N];
vector<int> g[N];
int main()
{IO;int T=1;//Pinit(1000000);//Cinit(1000);//cin>>T;while(T--){cin>>n>>m>>k;for(int i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i];while(m--){int u,v;cin>>u>>v;last[v]=max(last[v],u);}for(int i=1;i<=n;i++){last[i]=max(last[i],i);g[last[i]].push_back(i);}priority_queue<int,vector<int>,greater<int> > q;int now=k;for(int u=1;u<=n;u++){while(now<a[u]&&q.size()) now++,q.pop();if(now<a[u]) return cout<<-1<<'\n',0;now+=b[u];for(auto t:g[u]) q.push(c[t]),now--;}while(now<0&&q.size()) now++,q.pop();if(now<0) cout<<-1<<'\n';else{int res=0;while(q.size()) res+=q.top(),q.pop();cout<<res<<'\n';}}return 0;
}