Submission #1274815

#TimeUsernameProblemLanguageResultExecution timeMemory
1274815mehrzad3개의 봉우리 (IOI25_triples)C++20
56.74 / 100
2108 ms472120 KiB
#include "triples.h"
#include <bits/stdc++.h>
using namespace std;

static inline uint64_t encode(int i, int j, int k) {
    return ( (uint64_t)i << 40 ) | ( (uint64_t)j << 20 ) | (uint64_t)k;
}

void addTriple(int i, int j, int k, unordered_set<uint64_t> &S) {
    if (i < j && j < k) S.insert(encode(i, j, k));
}

/* main routine required by the statement */
long long count_triples(std::vector<int> H) {
    const int N = (int)H.size();
    vector<int> forward(N, -1), backward(N, -1);
    vector<vector<int>> forward_to(N), backward_to(N);

    for (int i = 0; i < N; ++i) {
        int f = i + H[i];
        if (f < N) {
            forward[i] = f;
            forward_to[f].push_back(i);
        }
        int b = i - H[i];
        if (b >= 0) {
            backward[i] = b;
            backward_to[b].push_back(i);
        }
    }

    unordered_set<uint64_t> triples;
    triples.reserve(N * 4);

    /* case 1 : a , b , a+b  (two forward edges) */
    for (int i = 0; i < N; ++i) {
        int j = forward[i];
        if (j == -1) continue;
        int k = forward[j];
        if (k == -1) continue;
        if ((long long)H[i] + H[j] == H[k]) addTriple(i, j, k, triples);
    }

    /* case 2 : a , a+b , b   (i -> j, middle largest) */
    for (int i = 0; i < N; ++i) {
        int j = forward[i];
        if (j == -1) continue;
        int D = H[j];
        if (D <= H[i]) continue;                 // D must be the largest
        int k = i + D;
        if (k >= N) continue;
        if (H[k] == D - H[i]) addTriple(i, j, k, triples);
    }

    /* case 3 : b , a+b , a   (k -> j, middle largest) */
    for (int k = 0; k < N; ++k) {
        int j = backward[k];
        if (j == -1) continue;
        int D = H[j];
        if (D <= H[k]) continue;
        int i = j - (D - H[k]);                  // i = j - b
        if (i < 0) continue;
        if (H[i] == D - H[k]) addTriple(i, j, k, triples);
    }

    /* case 4 : b , a , a+b   (j - H[j] = i, then k = j + H[i]) */
    for (int j = 0; j < N; ++j) {
        int i = backward[j];
        if (i == -1) continue;
        int hi = H[i];
        int k = j + hi;
        if (k >= N) continue;
        if (H[k] == hi + H[j]) addTriple(i, j, k, triples);
    }

    /* case 5 : a+b , a , b   (i -> k, j = k - H[k]) */
    for (int i = 0; i < N; ++i) {
        int k = forward[i];
        if (k == -1) continue;
        int j = backward[k];
        if (j <= i || j >= k) continue;
        if (backward[j] == i) addTriple(i, j, k, triples);
    }

    /* case 6 : a+b , b , a   (two forward edges to the same k) */
    for (int k = 0; k < N; ++k) {
        int diff = H[k];
        const vector<int> &vec = forward_to[k];
        if (vec.empty()) continue;
        // store indices in an unordered_set for O(1) existence test
        unordered_set<int> setVec(vec.begin(), vec.end());
        for (int i : vec) {
            int j = i + diff;
            if (j < k && setVec.find(j) != setVec.end()) {
                // diff = H[k] is already the distance j-i needed
                addTriple(i, j, k, triples);
            }
        }
    }

    /* pivot case – permutation 4 (b , a+b , a) */
    for (int p = 0; p < N; ++p) {
        const vector<int> &I = forward_to[p];
        const vector<int> &K = backward_to[p];
        if (I.empty() || K.empty()) continue;
        for (int i : I) {
            for (int k : K) {
                if (i >= k) continue;
                long j = (long)i + k - p;
                if (j <= i || j >= k || j >= N) continue;
                if (H[(int)j] == k - i) addTriple(i, (int)j, k, triples);
            }
        }
    }

    return (long long)triples.size();
}


#include <vector>
#include <algorithm>
using namespace std;

std::vector<int> construct_range(int M, int K) {
    vector<int> H;
    H.reserve(M);
    long long total = 0;                     // number of mythical triples found so far

    while ((int)H.size() < M && total < K) {
        int idx = (int)H.size();             // index of the new peak (0‑based)

        // The first two positions cannot form a triple yet
        if (idx < 2) {
            H.push_back(1);                 // any allowed height
            continue;
        }

        // cnt[v] = how many new triples would appear if we set H[idx] = v
        vector<int> cnt(idx + 1, 0);          // possible heights are 1..idx

        // enumerate all pairs (i, j) with i < j < idx
        for (int i = 0; i < idx - 1; ++i) {
            int hi = H[i];
            for (int j = i + 1; j < idx; ++j) {
                int hj = H[j];

                int a = j - i;                // distance i -> j
                int b = idx - j;              // distance j -> idx
                int c = a + b;                // distance i -> idx

                int v = -1;
                if (hi == a && hj == b) v = c;
                else if (hi == a && hj == c) v = b;
                else if (hi == b && hj == a) v = c;
                else if (hi == b && hj == c) v = a;
                else if (hi == c && hj == a) v = b;
                else if (hi == c && hj == b) v = a;

                if (v >= 1 && v <= idx) {
                    ++cnt[v];
                }
            }
        }

        // choose the height giving the most new triples
        int best_v = 1;
        int best_gain = cnt[1];
        for (int v = 2; v <= idx; ++v) {
            if (cnt[v] > best_gain) {
                best_gain = cnt[v];
                best_v = v;
            }
        }

        // if no gain is possible, just pick any legal height (1)
        if (best_gain <= 0) {
            best_v = 1;
            best_gain = 0;
        }

        H.push_back(best_v);
        total += best_gain;
    }

    // If we stopped because we reached M but still have fewer than K triples,
    // we simply return the constructed range (partial credit).  In practice,
    // with the greedy construction the condition total >= K is reached well
    // before M = 5000.
    return H;
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...