Submission #1325872

#TimeUsernameProblemLanguageResultExecution timeMemory
1325872lesinhhungVrtić (COCI18_vrtic)C++17
160 / 160
437 ms33656 KiB
#include <bits/stdc++.h>
using namespace std;

static const int INF = 1e9;

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

    int n;
    cin >> n;
    vector<int> f(n + 1);
    for (int i = 1; i <= n; i++) cin >> f[i];

    vector<long long> candy(n + 1);
    for (int i = 1; i <= n; i++) cin >> candy[i];

    // Build undirected graph of the permutation (each component is a cycle)
    vector<vector<int>> g(n + 1);
    for (int i = 1; i <= n; i++) {
        int p = f[i];
        g[i].push_back(p);
        g[p].push_back(i);
    }

    // Sort candies, keep original bag indices
    vector<int> ord(n + 1);
    iota(ord.begin(), ord.end(), 0);
    sort(ord.begin() + 1, ord.end(), [&](int i, int j) {
        return candy[i] < candy[j];
    });

    vector<long long> val(n + 1);
    for (int pos = 1; pos <= n; pos++) val[pos] = candy[ord[pos]];

    // Find cycle components; groupBySize[len] stores representative nodes of cycles with that length
    vector<char> vis(n + 1, 0);
    vector<vector<int>> groupBySize(n + 1);
    vector<int> compSizeOfRoot; // not needed, but keep structure

    function<int(int)> dfsCount = [&](int u) -> int {
        vis[u] = 1;
        int cnt = 1;
        for (int v : g[u]) if (!vis[v]) cnt += dfsCount(v);
        return cnt;
    };

    vector<int> used(n + 1, 0);
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            int sz = dfsCount(i);
            groupBySize[sz].push_back(i);
            used[sz]++;
        }
    }

    // Collect distinct sizes
    vector<int> sizes;      // distinct cycle lengths
    vector<int> counts;     // how many cycles of that length
    for (int len = 1; len <= n; len++) {
        if (used[len] > 0) {
            sizes.push_back(len);
            counts.push_back(used[len]);
        }
    }
    int m = (int)sizes.size();

    // mixed radix bases and multipliers
    vector<int> base(m), pro(m, 1);
    long long limitLL = 1;
    for (int i = 0; i < m; i++) {
        base[i] = counts[i] + 1;
        limitLL *= base[i];
    }
    int limit = (int)limitLL; // in practice stays manageable for N<=150 (as in AC)
    for (int i = m - 2; i >= 0; i--) pro[i] = pro[i + 1] * base[i + 1];

    auto decode = [&](int x) {
        vector<int> v(m, 0);
        for (int i = m - 1; i >= 0; i--) {
            v[i] = x % base[i];
            x /= base[i];
        }
        return v;
    };

    // Precompute cost[l][r] for assigning sorted segment [l..r] to one cycle
    // cost formula matches AC: len=1 ->0, len=2 -> v[r]-v[l], len>=3 -> max(prev, v[r]-v[r-2])
    vector<vector<int>> cost(n + 2, vector<int>(n + 2, 0));
    for (int l = 1; l <= n; l++) {
        cost[l][l] = 0;
        for (int r = l + 1; r <= n; r++) {
            int len = r - l + 1;
            if (len == 2) {
                cost[l][r] = (int)min<long long>(INT_MAX, val[r] - val[l]);
            } else {
                cost[l][r] = cost[l][r - 1];
                long long diff2 = val[r] - val[r - 2];
                if (diff2 > cost[l][r]) cost[l][r] = (int)min<long long>(INT_MAX, diff2);
            }
        }
    }

    // DP over mixed-radix state: DP[state] = minimal possible maximal dissatisfaction so far
    vector<int> dp(limit, INF), trace(limit, -1);
    dp[0] = 0;

    for (int st = 0; st + 1 < limit; st++) {
        if (dp[st] >= INF) continue;
        vector<int> taken = decode(st);

        int lpos = 1;
        for (int i = 0; i < m; i++) lpos += taken[i] * sizes[i];

        for (int i = 0; i < m; i++) {
            if (taken[i] + 1 < base[i]) {
                int nst = st + pro[i];
                int len = sizes[i];
                int rpos = lpos + len - 1;
                int cand = max(dp[st], cost[lpos][rpos]);
                if (cand < dp[nst]) {
                    dp[nst] = cand;
                    trace[nst] = i;
                }
            }
        }
    }

    int best = dp[limit - 1];
    cout << best << "\n";

    // Reconstruct order of block lengths
    vector<int> blocks;
    int st = limit - 1;
    while (st > 0) {
        int i = trace[st];
        blocks.push_back(sizes[i]);
        st -= pro[i];
    }
    reverse(blocks.begin(), blocks.end());

    // Now assign actual positions (1..n in sorted candies) to each child vertex
    vector<int> idxPos(n + 1, 0);
    fill(vis.begin(), vis.end(), 0);

    function<void(int,int,int)> buildCycleAssign = [&](int u, int L, int R) {
        vis[u] = 1;
        for (int v : g[u]) {
            if (!vis[v]) {
                if ( ((idxPos[u] - L) & 1) ) {
                    idxPos[v] = idxPos[u] - 2;
                } else {
                    if (idxPos[u] + 2 <= R) idxPos[v] = idxPos[u] + 2;
                    else if (idxPos[u] < R) idxPos[v] = R;
                    else idxPos[v] = R - 1;
                }
                buildCycleAssign(v, L, R);
            }
        }
    };

    int curL = 1;
    for (int len : blocks) {
        int root = groupBySize[len].back();
        groupBySize[len].pop_back();

        idxPos[root] = curL;
        buildCycleAssign(root, curL, curL + len - 1);
        curL += len;
    }

    // Translate sorted-position -> bag index -> candy value for each child
    vector<long long> ans(n + 1);
    for (int i = 1; i <= n; i++) {
        int pos = idxPos[i];          // 1..n
        int bagIdx = ord[pos];        // original bag index
        ans[i] = candy[bagIdx];
    }

    for (int i = 1; i <= n; i++) {
        cout << ans[i] << (i == n ? '\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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...