제출 #1272016

#제출 시각아이디문제언어결과실행 시간메모리
1272016sweetwibu2k8Džumbus (COCI19_dzumbus)C++20
0 / 110
28 ms2264 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (1LL<<60);

int N, M;
vector<ll> D;
vector<vector<int>> g;
vector<int> seen;

// DP returns triple of vectors dp0, dp1, dp2 for node u
// dp*_sz = number of possible good nodes in subtree (indices 0..sz)
struct Triple {
    vector<ll> dp0, dp1, dp2;
};

Triple dfs(int u, int p) {
    // initialize
    Triple cur;
    cur.dp0 = vector<ll>(1, 0);         // if u not chosen: 0 cost, 0 good nodes
    cur.dp1 = vector<ll>(1, D[u]);      // if u chosen but not connected yet: cost D[u], 0 good nodes inside so far
    cur.dp2 = vector<ll>();             // empty until it becomes possible
    int size_cur = 0; // number of good nodes accounted so far in these arrays

    for (int v : g[u]) if (v != p) {
        Triple ch = dfs(v, u);
        int s1 = size_cur;
        int s2 = (int)max({ch.dp0.size(), ch.dp1.size(), ch.dp2.size()}) - 1;
        int new_size = s1 + s2;

        vector<ll> ndp0(new_size+1, INF), ndp1(new_size+1, INF), ndp2(new_size+1, INF);

        // Helper: get cost arrays for child states (if index j out of range, cost = INF)
        auto cost0 = [&](int j)->ll { return (j >= 0 && j < (int)ch.dp0.size()) ? ch.dp0[j] : INF; };
        auto cost1 = [&](int j)->ll { return (j >= 0 && j < (int)ch.dp1.size()) ? ch.dp1[j] : INF; };
        auto cost2 = [&](int j)->ll { return (j >= 0 && j < (int)ch.dp2.size()) ? ch.dp2[j] : INF; };

        // Merge for dp0: parent not chosen -> child may be dp0 or dp2 only
        for (int i = 0; i <= s1; ++i) if (i < (int)cur.dp0.size()) {
            if (cur.dp0[i] >= INF) continue;
            for (int j = 0; j <= s2; ++j) {
                ll candi = min(cost0(j), cost2(j));
                if (candi >= INF) continue;
                ndp0[i+j] = min(ndp0[i+j], cur.dp0[i] + candi);
            }
        }

        // Merge for dp2 (parent already connected): child can be dp0, dp2, or dp1 (dp1 resolves to +1 count)
        if (!cur.dp2.empty()) {
            for (int i = 0; i <= s1; ++i) if (i < (int)cur.dp2.size()) {
                if (cur.dp2[i] >= INF) continue;
                for (int j = 0; j <= s2; ++j) {
                    // child dp0 or dp2: counts add j
                    if (cost0(j) < INF) ndp2[i+j] = min(ndp2[i+j], cur.dp2[i] + cost0(j));
                    if (cost2(j) < INF) ndp2[i+j] = min(ndp2[i+j], cur.dp2[i] + cost2(j));
                    // child dp1: when parent is selected, child pending resolves: child contributes +1
                    if (cost1(j) < INF) ndp2[i + j + 1] = min(ndp2[i + j + 1], cur.dp2[i] + cost1(j));
                }
            }
        }

        // Merge for dp1 (parent chosen but not connected yet)
        for (int i = 0; i <= s1; ++i) if (i < (int)cur.dp1.size()) {
            if (cur.dp1[i] >= INF) continue;
            for (int j = 0; j <= s2; ++j) {
                // child dp0 or dp2: parent remains pending
                if (cost0(j) < INF) ndp1[i+j] = min(ndp1[i+j], cur.dp1[i] + cost0(j));
                if (cost2(j) < INF) ndp1[i+j] = min(ndp1[i+j], cur.dp1[i] + cost2(j));
                // child dp1: connecting parent and child => parent becomes connected (+1), child becomes good (+1)
                if (cost1(j) < INF) {
                    // added good nodes: child gives j+1, plus parent +1 -> total + (j+2)
                    ndp2[i + j + 2] = min(ndp2[i + j + 2], cur.dp1[i] + cost1(j));
                }
            }
        }

        // Also dp2 could be created from dp0 if dp0 was empty? No: dp0 cannot create dp2.
        // Update cur with ndp*
        // Trim trailing INF entries possibly to reduce sizes
        auto trim = [&](vector<ll> &v) {
            int last = (int)v.size() - 1;
            while (last >= 0 && v[last] >= INF) --last;
            v.resize(last+1);
            if (v.empty()) v = vector<ll>(); // keep empty
        };

        cur.dp0 = ndp0; trim(cur.dp0);
        cur.dp1 = ndp1; trim(cur.dp1);
        cur.dp2 = ndp2; trim(cur.dp2);
        size_cur = (int)max({cur.dp0.size(), cur.dp1.size(), cur.dp2.size()}) - 1;
        if (size_cur < 0) size_cur = 0;
    } // end foreach child

    return cur;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> N >> M;
    D.assign(N, 0);
    for (int i = 0; i < N; ++i) cin >> D[i];
    g.assign(N, {});
    for (int i = 0; i < M; ++i) {
        int a,b; cin >> a >> b; --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    int Q; cin >> Q;
    vector<ll> S(Q);
    ll Smax = 0;
    for (int i = 0; i < Q; ++i) { cin >> S[i]; Smax = max(Smax, S[i]); }

    // find components and compute best_comp for each
    vector<int> vis(N,0);
    vector<vector<ll>> comps_best; // comps_best[k][c] = minimal cost to get c good nodes in that comp

    for (int i = 0; i < N; ++i) if (!vis[i]) {
        // BFS/DFS to mark component nodes
        vector<int> stack = {i};
        vis[i] = 1;
        for (int idx = 0; idx < (int)stack.size(); ++idx) {
            int u = stack[idx];
            for (int v : g[u]) if (!vis[v]) { vis[v] = 1; stack.push_back(v); }
        }
        // run tree DP with root = i (component is a tree by problem statement)
        Triple t = dfs(i, -1);
        int maxc = 0;
        if (!t.dp0.empty()) maxc = max(maxc, (int)t.dp0.size()-1);
        if (!t.dp2.empty()) maxc = max(maxc, (int)t.dp2.size()-1);
        vector<ll> best(maxc+1, INF);
        // best[c] = min(dp0[c], dp2[c]) (dp1 invalid at root)
        for (int c = 0; c <= maxc; ++c) {
            ll val = INF;
            if (c < (int)t.dp0.size()) val = min(val, t.dp0[c]);
            if (c < (int)t.dp2.size()) val = min(val, t.dp2[c]);
            best[c] = val;
        }
        // also possible to take c=0 with cost 0 even if not present
        if (best.size() == 0) best = vector<ll>(1, 0);
        else best[0] = min(best[0], 0LL);
        comps_best.push_back(best);
    }

    // global knapsack by value: dp[v] = minimal cost to achieve total v good nodes across processed components
    vector<ll> global(N+1, INF);
    global[0] = 0;
    for (auto &best : comps_best) {
        int sz = (int)best.size()-1;
        vector<ll> nxt(N+1, INF);
        for (int have = 0; have <= N; ++have) {
            if (global[have] >= INF) continue;
            // take c from this comp
            for (int c = 0; c <= sz; ++c) {
                if (best[c] >= INF) continue;
                if (have + c <= N) nxt[have + c] = min(nxt[have + c], global[have] + best[c]);
            }
        }
        global.swap(nxt);
    }

    // For each query S[i], find max v with global[v] <= S[i]
    for (int qi = 0; qi < Q; ++qi) {
        ll s = S[qi];
        int ans = 0;
        for (int v = 0; v <= N; ++v) {
            if (global[v] <= s) ans = v;
        }
        cout << ans << '\n';
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...