起初你有 \(k\) 个兵,你需要按顺序攻占 \(n\) 座城堡。为了占领第 \(i\) 座城堡,你需要至少 \(a_i\) 个士兵,士兵不会死,攻占成功后你可以获得 \(b_i\) 个士兵。攻占完一座城堡你可以派出至少一个兵驻守来获得这座城堡的分数 \(c_i\),你可以在你攻占完城堡 \(i\) 后立即派兵下车,或者在有向图上通向这个点的点处派兵下车。你需要在保证能攻占所有城堡的前提下,最大化你的得分。\(n \leq 5000, m\leq 3\times 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;
}