0w1

CFR 815 C. Karen and Supermarket

Problem Description:
There are N items, the i'th item costs C[i], and we have a coupon that can reduce its price by D[i]. However, for every coupon i to be effective, coupon X[i] must be used, i.e., i'th item bought. You have B units of money as your budget, find the maximum number of items you can buy.

Constraints:
1 ≤ N ≤ 5000
1 ≤ B ≤ 1e9
1 ≤ D[i] ≤ C[i] ≤ 1e9

Solution:
Not only does the dependency constitute a DAG, it is a rooted tree. We can come up with a DP solution:
dp[0][u][x]: minimum cost to buy x items, considering subtree with root u, given that u's father was not bought
dp[1][u][x]: minimum cost to buy x items, considering subtree with root u, given that u's father was bought
dp[2][u][x] = min(dp[0][u][x], dp[1][u][x])
T(u): time cost for subtree with root u
T(u) = u.chlidren.map { |v| T(v) } .inject(:+) + u.children.map { |v| v.size } .inject(:*)
However, as u.size ≥ u.children.map { |v| v.size } .inject(:+), and u.size ** 2 ≥ u.children.map { |v| v.size ** 2 } .inject(:+) + u.children.map { |v| v.size } .inject(:*), we can deduce that T(u) = O(u.size ** 2).

Code:

#include <bits/stdc++.h>

int Dp(int n, int b, const std::vector<int> &c, const std::vector<int> &d, const std::vector<int> &x) {
  std::vector<std::vector<int>> graph(n);
  for (int i = 1; i < n; ++i) {
    graph[x[i] - 1].emplace_back(i);
  }
  std::vector<std::vector<int>> dp[3];
  std::for_each(dp, dp + 3, [&](std::vector<std::vector<int>> &v) { v.resize(n); });
  std::function<void(int)> dfs = [&](int u) {
    dp[0][u] = { 0, c[u] };
    dp[1][u] = { 0x3f3f3f3f, c[u] - d[u] };
    for (int v : graph[u]) {
      dfs(v);
      auto merge = [&](const std::vector<int> &a, const std::vector<int> &b) {
        std::vector<int> c(a.size() + b.size() - 1, 0x3f3f3f3f);
        for (size_t i = 0; i < a.size(); ++i) {
          for (size_t j = 0; j < b.size(); ++j) {
            c[i + j] = std::min(c[i + j], a[i] + b[j]);
          }
        }
        return c;
      };
      dp[0][u] = merge(dp[0][u], dp[0][v]);
      dp[1][u] = merge(dp[1][u], dp[2][v]);
    }
    dp[2][u].resize(dp[0][u].size());
    std::for_each(dp[2][u].begin(), dp[2][u].end(), [&, i = 0](int &x) mutable { x = std::min(dp[0][u][i], dp[1][u][i]), ++i; });
  };
  dfs(0);
  return dp[2][0].size() - 1 - std::distance(dp[2][0].rbegin(), std::find_if(dp[2][0].rbegin(), dp[2][0].rend(), [&](int w) { return w <= b; }));
}

signed main() {
  std::ios::sync_with_stdio(false);
  int N, B;
  std::cin >> N >> B;
  std::vector<int> C(N), D(N), X(N);
  for (int i = 0; i < N; ++i) {
    std::cin >> C[i] >> D[i];
    if (i) std::cin >> X[i];
  }
  std::cout << Dp(N, B, C, D, X) << std::endl;
  return 0;
}