Submission #1181686

#TimeUsernameProblemLanguageResultExecution timeMemory
1181686sagnbaevv나일강 (IOI24_nile)C++20
Compilation error
0 ms0 KiB
#include <bits/stdc++.h>
using namespace std;

/*
    A Fenwick Tree (BIT) here is used for
    "range maximum queries" over prefix [1..i].
    We'll store fenwicks[i] = max over some subrange,
    and do standard Fenwick-based updates/queries.
*/
struct Fenwick {
    int n;
    vector<long long> fenwicks;
    Fenwick(int n_) : n(n_), fenwicks(n_+1, LLONG_MIN) {}

    // Get max in range [1..pos]
    long long query(int pos) {
        long long res = LLONG_MIN;
        while (pos > 0) {
            res = max(res, fenwicks[pos]);
            pos -= pos & (-pos);
        }
        return res;
    }

    // Update position pos to at least value val
    void update(int pos, long long val) {
        while (pos <= n) {
            fenwicks[pos] = max(fenwicks[pos], val);
            pos += pos & (-pos);
        }
    }
};

// This is the function you would implement/return in a competitive setting.
vector<long long> calculate_costs(
    const vector<int> &W,
    const vector<int> &A,
    const vector<int> &B,
    const vector<int> &E )
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N = (int)W.size();
    int Q = (int)E.size();

    // 1) Preprocess: 
    //    - Make a list of artifact indices, sorted by weight
    //    - Also store advantage[i] = A[i] - B[i]
    vector<int> idx(N);
    iota(idx.begin(), idx.end(), 0); // [0,1,...,N-1]
    sort(idx.begin(), idx.end(), [&](int i, int j){
        return W[i] < W[j];
    });

    vector<long long> sortedW(N), adv(N), sortedA(N);
    for(int i = 0; i < N; i++){
        sortedW[i] = W[idx[i]];
        adv[i]      = (long long)A[idx[i]] - B[idx[i]];
        sortedA[i]  = A[idx[i]];
    }

    // sum of all A[i], used later: cost = sumA - dp[N]
    long long sumA = 0LL;
    for(int i = 0; i < N; i++){
        sumA += sortedA[i];
    }

    // We'll answer each query E[j] by re-running the DP. 
    // (This is fine only for smaller constraints.)
    // Store results in res[] in the original order.
    vector<long long> res(Q);

    // A small helper function that performs the DP 
    // for a single D, returning the minimal total cost.
    auto solve_for_D = [&](long long Dval) {
        // DP array: dp[i] = maximum sum of adv among matched artifacts 
        // in the first i artifacts (1-based indexing to match Fenwicks usage).
        // We'll keep dp in a 0-based vector, but interpret dp[i] = dp up to i-th artifact
        vector<long long> dp(N+1, 0LL);

        // We'll keep a Fenwicks structure to help with
        // max( dp[j-1] + adv[j] ) for j in some range [L..(i-1)].
        Fenwick fenw(N);

        // Initialize Fenwicks to very negative for no overlap
        for(int i = 1; i <= N; i++){
            fenw.update(i, LLONG_MIN/2);
        }

        // We'll do a pointer "leftPtr" to find the earliest j
        // that can match with i. (i.e. sortedW[i-1] - sortedW[j-1] <= D)
        int leftPtr = 0; // We'll move it in sync with i
       
        for(int i = 1; i <= N; i++){
            // Option 1: skip artifact i => dp[i] = dp[i-1]
            dp[i] = dp[i-1];
            // Move leftPtr so that W[i-1] - W[leftPtr] <= D 
            // (meaning W[i-1] >= W[leftPtr] - D).
            // Actually we want all j in [leftPtr..(i-1)] satisfying sortedW[i-1] - sortedW[j-1] <= D.
            // So we need sortedW[j-1] >= sortedW[i-1] - D. We'll move leftPtr forward to ensure that.
            while(leftPtr < i) {
                if( sortedW[i-1] - sortedW[leftPtr] <= Dval ) {
                    break;
                }
                leftPtr++;
            }
            
            // Now any j in [leftPtr..(i-1)] is feasible to pair with i,
            // i.e. sortedW[i-1] - sortedW[j-1] <= D.
            if(leftPtr < i) {
                // We want: dp[i] = max( dp[i], adv[i-1] + max_{j in [leftPtr..i-1]}( dp[j-1] + adv[j-1] ) )
                // We'll query fenwicks for the maximum over j in [leftPtr..(i-1)] of [ dp[j-1] + adv[j-1] ].
                long long best_in_range = fenw.query(i-1); 
                // but fenw.query(i-1) = max over [1..(i-1)], we also want j >= leftPtr => we can do fenw.query(i-1) - fenw.query(leftPtr-1) 
                // BUT our Fenwicks is only storing prefix maxima. 
                // Instead, a simpler approach: do "best_in_range = fenw.query(i-1)" 
                // and also ensure we never updated fenwicks for positions < leftPtr with large values. 
                // => We can handle that by storing -8 for them as we advance leftPtr. 
                // For simplicity, we'll do a second Fenwicks approach that can do range queries. 
                // Or do a small trick: we do "up to i-1" but need to remove up to leftPtr-1. 
                // This requires a segment tree or Fenwicks with range updates. 
                //
                // => For clarity in this code, we'll do a simpler approach:
                //    We'll keep incrementally "disabling" positions that fall out of the feasible range 
                //    by updating them with -8.  That might be too slow for large N, but it's simpler to illustrate the DP logic.  

                // Because we want a simpler code demonstration, let's not be too fancy:
                // We'll do a binary search approach each time i: we want the maximum X[j] for j in [leftPtr..i-1].
                // That can be done with a segment tree that supports range-max queries. 
                // For demonstration, let's keep the Fenwicks as a segment tree approach with range queries.

                // Let us implement a simpler segment-tree structure quickly:

                // (To keep this code from getting too big, let's do a naive O(log N) range max with a standard segment tree.)
            }

        }

        // Actually let's do a more direct approach with a separate data structure:

        // We'll keep a *static* segment tree each time solve_for_D is called.
        // Re-build from scratch? That is still O(N log N), but simpler to code:

        // 1) We'll maintain dp[] in a forward loop.
        // 2) We'll also keep an array X[i] = dp[i-1] + adv[i-1], 
        //    so X[i] is the “value” we might query in [leftPtr..(i-1)].
        // 3) Use a segment tree to store X[] for quick range-max queries.

        // Let's rewrite the function fully but more streamlined:

        return 0LL; // (Placeholder)
    };


    // We’ll implement the final code with a clear structure (below).
    // Because mixing it all in one big function can be confusing,
    // we’ll define a small "solveOneD" function at the end.

    // We must gather the answers in an array "res", returning it at the end.
    // We'll do the real DP now (rewriting the above logic more cleanly).
    


    // --------- REIMPLEMENT A CLEAN VERSION WITH A SEGMENT TREE -----------
    
    // Prebuild a function that runs the O(N log N) DP for a single D:
    struct SegTree {
        int size;
        vector<long long> mx;

        SegTree(int n) : size(n), mx(4*n, LLONG_MIN) {}
        void build(const vector<long long> &arr, int idx, int l, int r) {
            if(l == r) {
                mx[idx] = arr[l];
                return;
            }
            int mid = (l+r)/2;
            build(arr, idx*2, l, mid);
            build(arr, idx*2+1, mid+1, r);
            mx[idx] = max(mx[idx*2], mx[idx*2+1]);
        }
        void build(const vector<long long> &arr) {
            build(arr, 1, 0, size-1);
        }

        long long query(int idx, int l, int r, int ql, int qr) {
            if(ql>r || qr<l) return LLONG_MIN;
            if(ql<=l && r<=qr) return mx[idx];
            int mid=(l+r)/2;
            return max(query(idx*2, l, mid, ql, qr),
                       query(idx*2+1, mid+1, r, ql, qr));
        }
        long long query(int L, int R) {
            if(L>R) return LLONG_MIN;
            return query(1, 0, size-1, L, R);
        }

        void update(int idx, int l, int r, int pos, long long val) {
            if(l==r) {
                mx[idx] = val;
                return;
            }
            int mid=(l+r)/2;
            if(pos<=mid) update(idx*2, l, mid, pos, val);
            else         update(idx*2+1, mid+1, r, pos, val);
            mx[idx] = max(mx[idx*2], mx[idx*2+1]);
        }
        void update(int pos, long long val) {
            update(1, 0, size-1, pos, val);
        }
    };

    // Re-construct sorted arrays so we can close over them easily:
    vector<long long> sW(N), sAdv(N), sA(N);
    for(int i=0; i<N; i++){
        sW[i]   = sortedW[i];
        sAdv[i] = adv[i];
        sA[i]   = sortedA[i];
    }

    // The function that does the DP for a single D:
    auto solveOneD = [&](long long Dval) -> long long {
        // dp[i] = best sum of advantages among matched artifacts from first i (1..i).
        vector<long long> dp(N+1, 0LL);

        // We'll keep X[i] = dp[i-1] + sAdv[i-1], i in [1..N],
        // so X[i] is the value to combine with sAdv[i-1] if we pair i with something else.
        // We'll store them in 0-based for the segment tree, i.e. X[i-1] for index i-1.
        vector<long long> X(N, LLONG_MIN);

        // Build segment tree over X
        SegTree segt(N);
        segt.build(X); // everything initially LLONG_MIN

        // We'll keep a pointer leftPtr and move it as needed.
        int leftPtr = 1; // meaning we are looking at dp array indexing from 1..N
        // (We'll do everything 1-based for dp.)

        for(int i=1; i<=N; i++){
            // default (skip i):
            dp[i] = dp[i-1];

            // move leftPtr so that sW[i-1]-sW[leftPtr-1] <= Dval
            // i.e. sW[leftPtr-1] >= sW[i-1] - Dval
            while(leftPtr <= i) {
                if(sW[i-1] - sW[leftPtr-1] <= Dval) {
                    break;
                }
                leftPtr++;
            }

            // now feasible j are in [leftPtr..(i-1)] 
            if(leftPtr <= i-1) {
                // we want dp[i] = max( dp[i], sAdv[i-1] + max_{j in [leftPtr..i-1]} ( dp[j-1] + sAdv[j-1] ) )
                // but dp[j-1] + sAdv[j-1] = X[j], where X[j] we store in seg-tree as X[j-1], careful with indices
                // Let seg-tree index be j-1 for X.
                int L = leftPtr-1;       // left index in 0-based
                int R = (i-1) - 1;       // right index in 0-based
                long long bestRange = segt.query(L, R); // range max in [L..R]
                if(bestRange != LLONG_MIN) {
                    long long candidate = sAdv[i-1] + bestRange;
                    dp[i] = max(dp[i], candidate);
                }
            }

            // after deciding dp[i], we must update X[i] = dp[i-1] + sAdv[i-1] in segtree:
            {
                int pos = i-1; // 0-based
                long long val = dp[i-1] + sAdv[i-1];
                segt.update(pos, val);
            }
        }

        // dp[N] = max advantage. cost = sumA - dp[N].
        return sumA - dp[N];
    };
    // Now we simply run solveOneD(D) for each query E[j].
    for(int j=0; j<Q; j++){
        long long Dval = (long long)E[j];
        res[j] = solveOneD(Dval);
    }

    return res;
}


// ---------------------------------------------------------------------------
// A small demonstration main() for local testing.
//
// If you only need the function, you can remove 'main()' and
// keep just the 'calculate_costs' function above.
//
#ifdef LOCAL_TEST

int main(){
    // Example from the problem statement:
    // W=[15, 12, 2, 10, 21], A=[5,4,5,6,3], B=[1,2,2,3,2], E=[5,9,1]
    vector<int> W = {15,12,2,10,21};
    vector<int> A = {5,4,5,6,3};
    vector<int> B = {1,2,2,3,2};
    vector<int> E = {5,9,1};

    auto ans = calculate_costs(W, A, B, E);
    // Should be [16, 11, 23].
    for(auto &x : ans){
        cout << x << "\n";
    }
    return 0;
}
#endif

Compilation message (stderr)

/usr/bin/ld: /tmp/ccOY82V5.o: in function `main':
grader.cpp:(.text.startup+0x30e): undefined reference to `calculate_costs(std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >)'
collect2: error: ld returned 1 exit status