Submission #1329833

#TimeUsernameProblemLanguageResultExecution timeMemory
1329833model_codeGuessing Game (EGOI23_guessinggame)C++20
100 / 100
556 ms1412 KiB
#include <bits/stdc++.h>
using namespace std;

/*
 * EGOI 2023 - Guessing Game
 * K = 7 solution (100 points) based on editorial Solution 6.
 *
 * For N <= 32: use Solution 1 (K = N-1, unique values). Simple and correct.
 * For N > 32: two-phase approach with K = 7.
 */

static const int BIG_M = 32;
static const int BIG_LOGM = 5;

// Compute segment tree value for position p in a 32-position tree.
// Returns shifted value 1..5.
int computeTreeValue(int p, const vector<bool>& visited) {
    for (int d = 2; d <= BIG_LOGM; d++) {
        int sz = BIG_M >> (d - 1);
        int l = (p / sz) * sz;
        int r = l + sz - 1;
        bool ok = true;
        for (int i = l; i <= r; i++) {
            if (!visited[i]) { ok = false; break; }
        }
        if (ok) return d - 1;
    }
    return BIG_LOGM; // 5 = singleton
}

// Segment tree decode for 32 positions (Case B)
pair<int,int> treeDecode(const vector<int>& vals, int L, int R, int next_val) {
    if (L == R) return {L, L};
    if (L + 1 == R) return {L, R};
    int mid = (L + R) / 2;

    int lp = -1, rp = -1, lc = 0, rc = 0;
    for (int i = L; i <= mid; i++)
        if (vals[i] == next_val) { lc++; lp = i; }
    for (int i = mid + 1; i <= R; i++)
        if (vals[i] == next_val) { rc++; rp = i; }

    if (lc >= 1 && rc >= 1) return {lp, rp};
    if (lc >= 1) return treeDecode(vals, mid + 1, R, next_val + 1);
    if (rc >= 1) return treeDecode(vals, L, mid, next_val + 1);
    return {L, R};
}

// ===================== Small N =====================

void phase1_small(int N) {
    cout << max(N - 1, 1) << "\n";
    cout.flush();
    for (int t = 0; t < N - 1; t++) {
        int h; cin >> h;
        cout << (t + 1) << "\n";
        cout.flush();
    }
}

void phase2_small(int N) {
    vector<int> A(N);
    for (int i = 0; i < N; i++) cin >> A[i];
    int K = max(N - 1, 1);
    vector<int> cnt(K + 1, 0);
    for (int i = 0; i < N; i++)
        if (A[i] >= 1 && A[i] <= K) cnt[A[i]]++;
    int g1 = 0, g2 = 1;
    for (int v = 1; v <= K; v++) {
        if (cnt[v] == 2) {
            bool first = true;
            for (int i = 0; i < N; i++) {
                if (A[i] == v) {
                    if (first) { g1 = i; first = false; }
                    else { g2 = i; break; }
                }
            }
            break;
        }
    }
    cout << g1 << " " << g2 << "\n";
    cout.flush();
}

// ===================== Large N =====================

void phase1_large(int N) {
    cout << 7 << "\n";
    cout.flush();

    int phase1_count = N - BIG_M;
    int half_N = N / 2;
    vector<bool> seen(N, false);

    for (int t = 0; t < phase1_count; t++) {
        int h; cin >> h;
        seen[h] = true;
        cout << 7 << "\n";
        cout.flush();
    }

    vector<int> special;
    special.reserve(BIG_M);
    for (int i = 0; i < N; i++)
        if (!seen[i]) special.push_back(i);

    long long S = 0;
    for (int idx : special) S = (S + idx) % half_N;

    vector<int> pos_of(N);
    for (int i = 0; i < BIG_M; i++)
        pos_of[special[i]] = i;

    vector<bool> tree_visited(BIG_M, false);

    for (int t = 0; t < BIG_M - 1; t++) {
        int h; cin >> h;
        int p = pos_of[h];
        tree_visited[p] = true;
        int val = computeTreeValue(p, tree_visited);
        if (val == BIG_LOGM) {
            int bit_idx = p / 2;
            if ((S >> bit_idx) & 1)
                val = BIG_LOGM + 1; // 6
        }
        cout << val << "\n";
        cout.flush();
    }
}

void phase2_large(int N) {
    int half_N = N / 2;
    vector<int> A(N);
    for (int i = 0; i < N; i++) cin >> A[i];

    vector<int> non7;
    for (int i = 0; i < N; i++)
        if (A[i] != 7) non7.push_back(i);

    int cnt = (int)non7.size();

    if (cnt == BIG_M) {
        // Case B: Emma wrote 1..6. Tree decode.
        vector<int> vals(BIG_M);
        for (int i = 0; i < BIG_M; i++) {
            vals[i] = A[non7[i]];
            if (vals[i] == 6) vals[i] = 5;
        }
        auto [p1, p2] = treeDecode(vals, 0, BIG_M - 1, 1);
        cout << non7[p1] << " " << non7[p2] << "\n";
        cout.flush();
        return;
    }

    if (cnt != BIG_M - 1) {
        cout << 0 << " " << 1 << "\n";
        cout.flush();
        return;
    }

    // Case A: Emma wrote 7. 31 non7 positions.
    long long sum31 = 0;
    for (int idx : non7) sum31 += idx;

    // For each candidate insertion point k (0..31), decode S and find Emma.
    // We also verify structural consistency of the tree.

    // Build a value array indexed by non7 position j
    vector<int> val31(31);
    for (int j = 0; j < 31; j++) val31[j] = A[non7[j]];

    // Collect all valid Emma candidates across all k values
    vector<int> candidates;

    for (int k = 0; k <= 31; k++) {
        // For insertion point k: non7[j] has tree_pos = j if j < k, else j+1.
        // Value-5/6 positions use pair_idx = tree_pos / 2.

        // Structural check: for each value-5/6 position (val = 5 or 6),
        // its pair partner (tree_pos XOR 1) should have val <= 4 or be Emma (pos k).
        // For each value-1..4 position, its pair partner should have val 5 or 6 or be Emma.

        // Build tree_pos -> val mapping
        int tp_val[32];
        memset(tp_val, -1, sizeof(tp_val));
        for (int j = 0; j < 31; j++) {
            int tp = (j < k) ? j : j + 1;
            tp_val[tp] = val31[j];
        }
        // tp_val[k] = -1 (Emma's position)

        bool structural_ok = true;
        for (int j = 0; j < 31; j++) {
            int tp = (j < k) ? j : j + 1;
            int partner = tp ^ 1;
            int my_val = val31[j];

            if (my_val == 5 || my_val == 6) {
                // Singleton: pair partner should have val <= 4 or be Emma
                if (partner != k && tp_val[partner] != -1) {
                    if (tp_val[partner] > 4) {
                        // Partner also has val 5 or 6. Both singletons in same pair.
                        // This means both were first in the pair, contradiction.
                        // Unless one of them is misidentified due to wrong k.
                        structural_ok = false;
                        break;
                    }
                }
            }
        }

        if (!structural_ok) continue;

        // Decode S from value-5/6 positions
        long long S_decoded = 0;
        for (int j = 0; j < 31; j++) {
            int tp = (j < k) ? j : j + 1;
            if (val31[j] == 6) {
                S_decoded |= (1LL << (tp / 2));
            }
        }

        long long emma_mod = (((S_decoded - sum31) % half_N) + half_N) % half_N;

        for (int option = 0; option < 2; option++) {
            long long ei = emma_mod + (long long)option * half_N;
            if (ei < 0 || ei >= N) continue;
            int e = (int)ei;
            if (A[e] != 7) continue;

            // Check insertion slot
            bool ok = true;
            if (k > 0 && e <= non7[k - 1]) ok = false;
            if (k < 31 && e >= non7[k]) ok = false;

            if (ok) {
                candidates.push_back(e);
            }
        }
    }

    if (candidates.empty()) {
        cout << 0 << " " << 1 << "\n";
    } else if (candidates.size() == 1) {
        int e = candidates[0];
        int e2 = (e + half_N) % N;
        // Both e and e2 should be checked, but e is already verified.
        // Output e and e2 to cover both mod-N/2 possibilities.
        cout << e << " " << e2 << "\n";
    } else {
        // Multiple candidates. Output first two distinct ones.
        sort(candidates.begin(), candidates.end());
        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());
        int g1 = candidates[0];
        int g2 = (candidates.size() >= 2) ? candidates[1] : g1;
        cout << g1 << " " << g2 << "\n";
    }
    cout.flush();
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int P, N;
    cin >> P >> N;
    if (N <= BIG_M) {
        if (P == 1) phase1_small(N);
        else phase2_small(N);
    } else {
        if (P == 1) phase1_large(N);
        else phase2_large(N);
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...