제출 #1339593

#제출 시각아이디문제언어결과실행 시간메모리
1339593lucas1105503개의 봉우리 (IOI25_triples)C++20
78.89 / 100
2095 ms17132 KiB
#include <bits/stdc++.h>

using namespace std;

long long count_triples(vector<int> H)
{
    const int N = static_cast<int>(H.size());

    long long cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0,
              cnt5 = 0, cnt6 = 0, equal_cnt = 0;

    /* ---------- assignment 1 ---------- */
    for (int i = 0; i < N; ++i) {
        int j = i + H[i];
        if (j >= N) continue;
        int b = H[j];
        int k = j + b;
        if (k >= N) continue;
        if (H[k] == H[i] + b) ++cnt1;
    }

    /* ---------- assignment 2 ---------- */
    for (int i = 0; i < N; ++i) {
        int j = i + H[i];
        if (j >= N) continue;
        int b = H[j] - H[i];
        if (b <= 0) continue;
        int k = j + b;
        if (k >= N) continue;
        if (H[k] == b) ++cnt2;
    }

    /* ---------- assignment 3 ---------- */
    for (int j = 0; j < N; ++j) {
        int i = j - H[j];
        if (i < 0) continue;
        int b = H[i];
        int k = j + b;
        if (k >= N) continue;
        if (H[k] == H[j] + b) ++cnt3;
    }

    /* ---------- assignment 5 ---------- */
    for (int j = 0; j < N; ++j) {
        int i = j - H[j];
        if (i < 0) continue;
        int b = H[i] - H[j];
        if (b <= 0) continue;
        int k = j + b;
        if (k >= N) continue;
        if (H[k] == b) ++cnt5;
    }

    /* ---------- assignment 6 ---------- */
    for (int j = 0; j < N; ++j) {
        int k = j + H[j];
        if (k >= N) continue;
        int a = H[k];
        int i = j - a;
        if (i < 0) continue;
        if (H[i] == a + H[j]) ++cnt6;
    }

    /* ---------- assignment 4 (group i+H[i] = k-H[k]) ---------- */
    // groups[T] = list of k such that k - H[k] == T   (T = “key”)
    unordered_map<int, vector<int>> groups;
    groups.reserve(N * 2);
    for (int k = 0; k < N; ++k) {
        int T = k - H[k];
        groups[T].push_back(k);            // k grows, so each vector stays sorted
    }

    for (int i = 0; i < N; ++i) {
        int T = i + H[i];
        auto it = groups.find(T);
        if (it == groups.end()) continue;   // no k with the needed key

        const vector<int>& ks = it->second;
        // first k that is > i
        auto posIter = upper_bound(ks.begin(), ks.end(), i);
        int H_i = H[i];

        for (auto kIt = posIter; kIt != ks.end(); ++kIt) {
            int k = *kIt;
            int j = k - H_i;
            if (j >= N) break;               // larger k → larger j, so we can stop
            // i < j < k holds automatically for the chosen ks
            if (H[j] == k - i) ++cnt4;
        }
    }

    long long total = cnt1 + cnt2 + cnt3 + cnt4 + cnt5 + cnt6;

    /* ---------- triples with equal distances (a = b) ----------
       These triples were counted twice (once in the main total and
       once in the equal‑distance special case), therefore we subtract
       them once at the end.                                         */
    for (int i = 0; i < N; ++i) {
        int a = H[i];

        // case 1 : distance = a   (i → j → k, with j = i+a, k = i+2a)
        int j = i + a;
        if (j < N) {
            int k = i + 2 * a;
            if (k < N) {
                bool ok = (H[j] == a && H[k] == 2 * a) ||
                          (H[j] == 2 * a && H[k] == a);
                if (ok) ++equal_cnt;
            }
        }

        // case 2 : distance = 2a   (i → j (a) → k (2a), but we treat a = H[i]/2)
        if (a % 2 == 0) {
            int a2 = a / 2;
            if (a2 > 0) {
                j = i + a2;
                int k = i + a;                     // i + 2*a2 = i + a
                if (j < N && k < N) {
                    if (H[j] == a2 && H[k] == a2) ++equal_cnt;
                }
            }
        }
    }

    return total - equal_cnt;
}



/* -------------------------------------------------------------
   2.  greedy_builder – builds a candidate array from (h0,h1)
   ------------------------------------------------------------- */
static vector<int> greedy_builder(int N, int h0, int h1,
                                  int D, int max_h)
{
    vector<int> H(N, 1);
    H[0] = h0;
    H[1] = h1;

    vector<int> cnt(max_h + 1, 0);
    vector<int> last(max_h + 1, 0);
    int version = 0;
    const int twoD = 2 * D;

    for (int k = 2; k < N; ++k) {
        ++version;
        int best_cnt = 0;
        int best_missing = 1;
        int i_start = k - twoD;
        if (i_start < 0) i_start = 0;

        for (int i = i_start; i < k; ++i) {
            int hi = H[i];
            int s = k - i;
            if (hi >= s) continue;

            // ----- left candidate j = i + hi -----
            int j = i + hi;
            if (j < k) {
                int a = hi;
                int b = s - hi;
                int hj = H[j];
                bool ok = (hj == a || hj == b || hj == s) &&
                          !(a != b && hi == hj);
                if (ok) {
                    int missing = 2 * s - hi - hj;
                    if (1 <= missing && missing <= max_h) {
                        if (last[missing] != version) {
                            cnt[missing] = 1;
                            last[missing] = version;
                        } else {
                            ++cnt[missing];
                        }
                        if (cnt[missing] > best_cnt) {
                            best_cnt = cnt[missing];
                            best_missing = missing;
                        }
                    }
                }
            }

            // ----- right candidate j2 = k - hi -----
            int j2 = k - hi;
            if (j2 > i && j2 != i + hi) {
                int a = s - hi;
                int b = hi;
                int hj = H[j2];
                bool ok = (hj == a || hj == b || hj == s) &&
                          !(a != b && hi == hj);
                if (ok) {
                    int missing = 2 * s - hi - hj;
                    if (1 <= missing && missing <= max_h) {
                        if (last[missing] != version) {
                            cnt[missing] = 1;
                            last[missing] = version;
                        } else {
                            ++cnt[missing];
                        }
                        if (cnt[missing] > best_cnt) {
                            best_cnt = cnt[missing];
                            best_missing = missing;
                        }
                    }
                }
            }
        }

        H[k] = (best_cnt > 0) ? best_missing : 1;
    }
    return H;
}

/* -------------------------------------------------------------
   3.  construct_range – the whole construction routine
   ------------------------------------------------------------- */
vector<int> construct_range(int M, int K)
{
    const int N = max(3, M);                 // we always use exactly N = M (M>=3 in tests)
    const int max_h = N - 1;
    int D = (N - 1) / 2;
    if (D == 0) D = 1;

    long long best_T = -1;
    vector<int> best_H;

    /* ----- helper: evaluate a candidate and keep the best one ----- */
    auto evaluate = [&](const vector<int>& H) {
        long long T = count_triples(H);
        if (T > best_T) {
            best_T = T;
            best_H = H;
            if (best_T >= K) throw runtime_error("enough triples");
        }
    };

    /* ----- deterministic patterns ----- */
    auto add_pattern = [&](const vector<int>& pat) {
        int repeats = N / static_cast<int>(pat.size()) + 1;
        vector<int> H;
        H.reserve(N);
        for (int i = 0; i < repeats; ++i) H.insert(H.end(), pat.begin(), pat.end());
        H.resize(N);
        evaluate(H);
    };

    add_pattern({1, 1, 2});
    add_pattern({1, 2, 1});
    add_pattern({2, 1, 1});

    // a2 pattern – 4 on positions whose block‑index %3 ==0
    vector<int> H(N);
    for (int i = 0; i < N; ++i) {
        if (i % 2 == 0) {                     // even index
            int pos = i / 2;
            H[i] = (pos % 3 == 0) ? 4 : 2;
        } else {                               // odd index
            int pos = (i - 1) / 2;
            H[i] = (pos % 3 == 0) ? 4 : 2;
        }
    }
    evaluate(H);

    /* ----- start pairs for the greedy builder ----- */
    unordered_set<long long> start_pairs;     // encode pair (h0,h1) in a 64‑bit key
    auto encode = [&](int a, int b) -> long long { return (static_cast<long long>(a) << 32) | static_cast<unsigned int>(b); };

    int limit = min(20, max_h);
    for (int h0 = 1; h0 <= limit; ++h0)
        for (int h1 = 1; h1 <= limit; ++h1)
            start_pairs.insert(encode(h0, h1));

    start_pairs.insert(encode(max_h, max_h));
    start_pairs.insert(encode(max_h, 1));
    start_pairs.insert(encode(1, max_h));
    if (max_h >= 2) {
        start_pairs.insert(encode(max_h - 1, max_h - 1));
        start_pairs.insert(encode(max_h - 2, max_h - 2));
    }

    mt19937_64 rnd(123456789ULL);
    for (int i = 0; i < 30; ++i) {
        int h0 = uniform_int_distribution<int>(1, max_h)(rnd);
        int h1 = uniform_int_distribution<int>(1, max_h)(rnd);
        start_pairs.insert(encode(h0, h1));
    }

    vector<pair<int,int>> start_list;
    start_list.reserve(start_pairs.size());
    for (auto key : start_pairs) {
        int h0 = static_cast<int>(key >> 32);
        int h1 = static_cast<int>(key & 0xffffffff);
        start_list.emplace_back(h0, h1);
    }
    shuffle(start_list.begin(), start_list.end(),
            mt19937_64(987654321ULL));

    /* ----- greedy builder for every start pair ----- */
    try {
        for (auto [h0, h1] : start_list) {
            int h0c = max(1, min(max_h, h0));
            int h1c = max(1, min(max_h, h1));
            vector<int> cand = greedy_builder(N, h0c, h1c, D, max_h);
            evaluate(cand);
        }
    } catch (const runtime_error&) {
        // we already hit K – just keep the current best
    }

    /* ----- hill climbing if needed ----- */
    if (best_T < K) {
        vector<int> cur_H = best_H;
        long long cur_T = best_T;

        // values we are allowed to change to (small numbers + the maximal one)
        vector<int> cand_vals;
        int small_limit = min(N, 30);
        for (int v = 1; v <= small_limit; ++v) cand_vals.push_back(v);
        if (max_h > small_limit) cand_vals.push_back(max_h);
        sort(cand_vals.begin(), cand_vals.end());
        cand_vals.erase(unique(cand_vals.begin(), cand_vals.end()), cand_vals.end());

        mt19937_64 rnd_hc(987654321ULL);
        uniform_int_distribution<int> idx_dist(0, N - 1);
        uniform_int_distribution<int> val_dist(0, static_cast<int>(cand_vals.size()) - 1);

        for (int step = 0; step < 20000 && best_T < K; ++step) {
            int i = idx_dist(rnd_hc);
            int new_val = cand_vals[val_dist(rnd_hc)];
            if (new_val == cur_H[i]) continue;

            int old = cur_H[i];
            cur_H[i] = new_val;
            long long new_T = count_triples(cur_H);
            if (new_T > cur_T) {
                cur_T = new_T;
                if (new_T > best_T) {
                    best_T = new_T;
                    best_H = cur_H;
                    if (best_T >= K) break;
                }
            } else {
                cur_H[i] = old;   // revert
            }
        }
    }

    /* ----- final safety clamp ----- */
    vector<int> out_H(N);
    for (int i = 0; i < N; ++i) {
        int v = best_H[i];
        if (v < 1) v = 1;
        if (v > max_h) v = max_h;
        out_H[i] = v;
    }
    out_H.resize(N);
    return out_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...