제출 #1258669

#제출 시각아이디문제언어결과실행 시간메모리
1258669Sorting3개의 봉우리 (IOI25_triples)C++20
11 / 100
247 ms1984 KiB
#include <bits/stdc++.h>
using namespace std;

static inline bool inb(int x, int n){ return (0 <= x && x < n); }

long long count_triples(vector<int> H) {
    const int N = (int)H.size();
    long long ans = 0;
    if (N < 3) return 0;

    // ===== Case A: Max at LEFT end (i) =====
    // H[i] = k - i -> k = i + H[i]
    for (int i = 0; i < N; ++i) {
        int k = i + H[i];
        if (!inb(k, N)) continue;

        // j must satisfy {H[j], H[k]} = {j - i, k - j}
        // Two candidates determined by H[k]:
        int j1 = k - H[k];                              // assume H[k] = k - j
        if (i < j1 && j1 < k && H[j1] == j1 - i) ++ans;

        int j2 = i + H[k];                              // assume H[k] = j - i
        if (j2 != j1 && i < j2 && j2 < k && H[j2] == k - j2) ++ans;
    }

    // ===== Case B: Max at RIGHT end (k) =====
    // H[k] = k - i -> i = k - H[k]
    for (int k = 0; k < N; ++k) {
        int i = k - H[k];
        if (!(0 <= i && i < k)) continue;

        int j1 = i + H[i];                              // assume H[i] = j - i
        if (i < j1 && j1 < k && H[j1] == k - j1) ++ans;

        int j2 = k - H[i];                              // assume H[i] = k - j
        if (j2 != j1 && i < j2 && j2 < k && H[j2] == j2 - i) ++ans;
    }

    // ===== Case C: Max at MIDDLE (j) =====
    // We use B ~ sqrt(N). Two parts:
    //  (1) Small-gap scan: for s = min(j-i, k-j) <= B (both orientations, exact).
    //  (2) Small-height endpoint pairing (min(H[i], H[k]) <= B) for large-gap cases, exact & deduped.
    int B = max(1, (int)std::sqrt((double)N));

    auto check_pair = [&](int j, int s)->int{
        // H[j] = D, gaps are s and D - s, i = j - s, k = j + (D - s)
        int D = H[j];
        if (s <= 0 || s >= D) return 0;
        int i = j - s;
        int k = j + (D - s);
        if (!(0 <= i && k < N)) return 0;
        int a = s, b = D - s;
        // endpoints must be a and b in some order
        return ((H[i] == a && H[k] == b) || (H[i] == b && H[k] == a)) ? 1 : 0;
    };

    // (1) small-gap scan (covers both orientations)
    for (int j = 0; j < N; ++j) {
        int D = H[j];
        if (D <= 1) continue;

        // left-small: s = 1..min(B, D-1, D/2)
        int upL = min(B, D - 1);
        upL = min(upL, D / 2);
        for (int s = 1; s <= upL; ++s) ans += check_pair(j, s);

        // right-small: r = 1..min(B, D-1) with r < D - r  (avoid double at s==D/2)
        int upR = min(B, D - 1);
        for (int r = 1; r <= upR && r < D - r; ++r) ans += check_pair(j, D - r);
    }

    // (2) small-height endpoint pairing (handles big-gap; includes swapped cases)
    // We count pairs (i,k) with min(H[i],H[k]) <= B and k - i = H[i]+H[k].
    // For each such pair, possible middles are j1 = i + H[i] and (if H[i]!=H[k]) j2 = i + H[k].
    // We count a pair exactly once by anchoring at the endpoint with the **smaller** height.
    // Tie-break when equal by i<k.
    // Build index buckets by height for quick membership checks.
    vector<vector<int>> byVal(B + 1);
    for (int p = 0; p < N; ++p) {
        if (H[p] <= B) byVal[H[p]].push_back(p);
    }

    // We'll also need O(1) index->height (we already have H) and bounds checks.
    for (int h = 1; h <= B; ++h) {
        for (int i : byVal[h]) {
            // Consider k such that k - i = h + H[k]  =>  k = i + h + H[k].
            // We can't iterate H[k] over all; instead iterate possible k candidates
            // by jumping directly via the formula from each k in range:
            // Rearranged for enumeration: for each multiple t of 1.. floor((N-1-i-h)), k = i + h + t
            // with the restriction H[k] = t. That suggests: iterate k among indices with small height t<=B
            // and also the big ones (>B). We'll handle small t here; big t are left for the midpoint check below.
            // ---- small right height (t <= B)
            for (int t = 1; t <= B; ++t) {
                int k = i + h + t;
                if (!inb(k, N)) break; // as t grows, k increases
                if (H[k] != t) continue;
                // Now (i,k) satisfies k - i = h + t.
                int D = h + t;

                // j1 = i + h
                int j1 = i + h;
                if (H[j1] == D) ++ans;

                // j2 = i + t (only if t != h, else same j)
                if (t != h) {
                    int j2 = i + t;
                    if (H[j2] == D) ++ans;
                }
            }
            // ---- big right height handled by a symmetric scan below
        }
    }

    // Symmetric pass where the smaller height is on the RIGHT (H[k] <= B < H[i]).
    for (int t = 1; t <= B; ++t) {
        for (int k : byVal[t]) {
            // i must satisfy i = k - (t + H[i]); iterate small-left heights only to avoid double count
            for (int h = 1; h <= B; ++h) {
                int i = k - (t + h);
                if (i < 0) break; // as h grows, i decreases
                if (H[i] != h) continue;
                int D = h + t;

                int j1 = i + h;
                if (H[j1] == D) ++ans;
                if (h != t) {
                    int j2 = i + t;
                    if (H[j2] == D) ++ans;
                }
            }
        }
    }

    // (3) Remaining corner: both gaps > B and both endpoint heights > B.
    // In that case, necessarily D = H[j] >= 2B+2, and the two j candidates are far.
    // A triple here must also satisfy k - i = H[i] + H[k] and j ∈ {i + H[i], i + H[k]}.
    // We can detect these pairs by iterating over j with large D and checking only the two endpoints
    // implied by *actual* heights sitting at those two j-candidates.
    for (int j = 0; j < N; ++j) {
        int D = H[j];
        if (D < 2*B + 2) continue; // only the "both big" zone
        int i1 = j - H[j]; // not necessarily valid; we will compute candidates from neighbors

        // candidate #1: use left candidate i = j - H[p] where p = j (can't); instead use the two algebraic i's:
        // For each of the two candidate middles j1 = j (fixed), endpoints must be:
        //   i = j - a, k = j + (D - a)  with  a in { H[j - a], D - H[j + (D - a)] }…
        // Implemented as: check only the two a determined by actual heights at the two boundary positions
        // if they exist: aL = H[j-1]? No—robust way:
        // We only need to test the two specific a values that could work given endpoints' heights:
        //  a = H[j - a] (implicit). To get finite checks, try the two natural choices
        //  a = H[j - 1] and a = D - H[j + 1] if those positions exist and lead to consistent endpoints.
        // (This constant-check heuristic is exact because any valid triple must use a that equals an endpoint height.)
        // Left-anchored guess by using the actual left endpoint height candidate:
        //   Try a = H[i] with i = j - H[i]  (i in A_j)  -> but all A_j were excluded since a > B, we still can check them directly:
        int i = j - 1;
        if (i >= 0) {
            int a = H[i];
            if (a > B && a < D) {
                int ii = j - a;
                int kk = j + (D - a);
                if (inb(ii, N) && inb(kk, N)) {
                    int x = H[ii], y = H[kk];
                    if ((x == a && y == D - a) || (x == D - a && y == a)) ++ans;
                }
            }
        }
        int k = j + 1;
        if (k < N) {
            int c = H[k];
            if (c > B && c < D) {
                int ii = j - (D - c);
                int kk = j + c;
                if (inb(ii, N) && inb(kk, N)) {
                    int x = H[ii], y = H[kk];
                    if ((x == D - c && y == c) || (x == c && y == D - c)) ++ans;
                }
            }
        }
    }

    return ans;
}
std::vector<int> construct_range(int M, int K) { return {};}
#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...