CodeForces - 1271D

3 篇文章 0 订阅

显然对于每个城堡,派人越晚越好,我们令每个城堡只会在进行到最晚的能派人到这个城堡的时候考虑是否派人,对于派人,攻占完每一个城堡后考虑派人,显然先考虑重要性最大的。

那么我们就可以进行 dp 了,设 $dp[i][j]$ 表示攻占完第 $i$ 个城堡后,有 $j$ 个人的答案。

枚举当前城堡打完后会派出去几个人进行转移。

```
#include <bits/stdc++.h>
#define mp(x, y) make_pair(x, y)
#define pb emplace_back
#define FOR(x, l, r) for(int x = l, _##x = int(r); x <= _##x; x++)
#define DO(x, r, l) for(int x = r, _##x = int(l); x >= _##x; x--)
#define vi vector
#define ALL(x) x.begin(), x.end()
#define AL(x) x.begin() + 1, x.end()
#define X first
#define Y second

using namespace std;

const int MOD = 1e9 + 7;
const double eps = 1e-11;

template<class T>
using vi2 = vector<vector<T>>;
using ll = long long;
using pii = pair<int, int>;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    auto solve = [&] () {
        int n, m, k, tk = 0;
        cin >> n >> m >> k;
        tk = k;
        vi<int> a(n + 1), b(n + 1), c(n + 1), mto(n + 1);
        vi2<int> go(n + 1);   // 当前城堡能派人到的城堡重要值
        FOR(i, 1, n) cin >> a[i] >> b[i] >> c[i], tk += b[i];
        FOR(i, 1, n) mto[i] = i;
        FOR(i, 1, m) {
            int u, v;
            cin >> u >> v;
            mto[v] = max(mto[v], u);  // 找到最大的能向当前城堡派人的城堡编号
        }
        FOR(i, 1, n) {
            go[mto[i]].pb(c[i]);
        }
        FOR(i, 1, n) sort(ALL(go[i]));
        FOR(i, 1, n) {
            go[i].pb(0);
            reverse(ALL(go[i]));
            FOR(j, 1, go[i].size() - 1) go[i][j] = go[i][j - 1] + go[i][j];
            // 从大到小排序,求前缀和。
        }
        vi2<int> dp(n + 1, vi<int>(tk + 1, -1));
        dp[0][k] = 0;
        FOR(i, 0, n - 1) {
            FOR(j, 0, tk) {
                if(dp[i][j] == -1 || j < a[i + 1]) continue;
                FOR(t, 0, go[i + 1].size() - 1) dp[i + 1][j + b[i + 1] - t] = max(dp[i + 1][j + b[i + 1] - t], dp[i][j] + go[i + 1][t]);
            }
        } 
        int ans = -1;
        FOR(j, 0, tk) ans = max(ans, dp[n][j]);
        cout << ans << endl;
    }; 
    int t = 1;
    // cin >> t;
    // scanf("%d", &t);
    while(t--) solve();
    return 0;
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值