起初你有 (k) 个兵,你需要按顺序攻占 (n) 座城堡。为了占领第 (i) 座城堡,你需要至少 (a_i) 个士兵,士兵不会死,攻占成功后你可以获得 (b_i) 个士兵。攻占完一座城堡你可以派出至少一个兵驻守来获得这座城堡的分数 (c_i),你可以在你攻占完城堡 (i) 后立即派兵下车,或者在有向图上通向这个点的点处派兵下车。你需要在保证能攻占所有城堡的前提下,最大化你的得分。(n leq 5000, mleq 3 imes 10^5),队伍中的人数无论如何不会超过 (5000)
Solution
对于城堡 (i),如果要对它派兵,那么一定会在最后一个能向他派兵的地方派兵
于是我们只需要考察其中的 (n) 条边即可
设 (f[i][j]) 表示在第 (i) 个城堡处,还剩 (j) 个士兵的最大收益
类似 (01) 背包的暴力转移
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5005;
const int K = 5001;
int n,m,k,r[N],a[N],b[N],c[N],f[N][N];
vector <int> g[N];
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=n;i++) r[i]=i;
for(int i=1;i<=m;i++) {
int u,v;
cin>>u>>v;
r[v]=max(r[v],u);
}
for(int i=1;i<=n;i++) {
g[r[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]+b[i];j<=K;j++) f[i][j]=f[i-1][j-b[i]];
for(int q:g[i]) {
for(int j=0;j<=K;j++) //!
f[i][j]=max(f[i][j],f[i][j+1]+c[q]);
}
}
int ans = *max_element(f[n],f[n]+K);
if(ans<0) cout<<-1;
else cout<<ans;
}