제출 #1341044

#제출 시각아이디문제언어결과실행 시간메모리
1341044yogesh_saneHotter Colder (IOI10_hottercolder)C++20
93.75 / 100
470 ms8220 KiB
#include "grader.h"
#include <algorithm>

using namespace std;

// hcdp[i] stores the maximum range size solvable with i guesses remaining.
long long hcdp[50];
bool is_initialized = false;

/**
 * Pre-calculates the maximum solvable ranges using the DP recurrence.
 * The recurrence hcdp[i] = hcdp[i-2] + 2^(i-1) defines the strategy's reach.
 */
void initialize_dp() {
    is_initialized = true;
    hcdp[0] = 1;
    hcdp[1] = 1;
    hcdp[2] = 3;
    hcdp[3] = 5;
    for (int i = 4; i < 45; i++) {
        hcdp[i] = hcdp[i - 2] + (1LL << (i - 1));
    }
}

/**
 * Standard Mirror Search:
 * Narrows down the range [start, end] using the 'last_guess' as a pivot.
 * Targets the midpoint of the current range for the next boundary.
 */
int mirror_search(int start, int end, int last_guess) {
    while (start < end) {
        int next_guess = start + end - last_guess;

        // Adjust for parity to ensure the boundary falls correctly
        if ((start + end) % 2 == 1) {
            if (next_guess > (start + end) / 2) next_guess++;
            else next_guess--;
        }

        // Avoid repeating the same guess
        if (next_guess == last_guess) {
            next_guess = (last_guess < end) ? last_guess + 1 : last_guess - 1;
        }

        int result = Guess(next_guess);
        if (result == 0) return (next_guess + last_guess) / 2;

        // If 'Colder' while moving up, or 'Hotter' while moving down, 
        // the target is in the lower half.
        if ((result < 0 && next_guess > last_guess) || (result > 0 && next_guess < last_guess)) {
            end = (next_guess + last_guess + 1) / 2 - 1;
        } else {
            start = (next_guess + last_guess) / 2 + 1;
        }
        last_guess = next_guess;
    }
    return start;
}

int HC(int N) {
    if (!is_initialized) initialize_dp();
    if (N == 1) return 1;

    // Base case for small N to save initial queries
    if (N <= 3) {
        Guess(1);
        int res = Guess(N);
        return (res == 1) ? N : (res == -1 ? 1 : 2);
    }

    // Determine total guesses available based on N
    int guesses_left = 0;
    while ((1LL << guesses_left) > N * 3 - 2 == false) guesses_left++;
    guesses_left -= 3;

    int mid = (2 + N) / 2;
    Guess(mid - 2);
    int second_guess = Guess(mid);

    if (second_guess == 0) return mid - 1;

    int range_start, range_end, last_guess;

    if (second_guess < 0) { // Target is in the lower half: [1, mid-2]
        last_guess = 1;
        int res = Guess(1);
        range_start = 1;
        range_end = mid;

        if (res == 0) return (1 + mid) / 2;
        if (res < 0) range_start = (1 + mid) / 2 + 1;
        else range_end = mid / 2;

        if (range_start == range_end) return range_start;

        // Handle edge cases for low remaining guesses
        if (guesses_left <= 2 && range_start == 1) {
            int final_res = Guess(3);
            if (guesses_left == 2 && final_res == 1) return Guess(5) + 4;
            return final_res + 2;
        }

        // DP-guided search loop
        while (range_start != range_end) {
            guesses_left--;
            int next_target = hcdp[guesses_left - 1] * 2 + range_start * 2 - 1;
            if (next_target + range_end - range_start >= N) 
                next_target = N - range_end + range_start;

            int res_loop = Guess(next_target);
            if (res_loop == 0) return (1 + next_target) / 2;
            
            if (res_loop < 0) {
                range_end = next_target / 2;
                if (range_start == range_end) return range_start;
                
                guesses_left--;
                Guess(range_start);
                if (range_start > 1) return mirror_search(range_start, range_end, range_start);
            } else {
                range_start = (1 + next_target) / 2 + 1;
                return mirror_search(range_start, range_end, next_target);
            }
        }
        return range_start;

    } else { // Target is in the upper half: [mid, N]
        last_guess = N;
        int res = Guess(N);
        range_start = mid;
        range_end = N;

        if (res == 0) return (N + mid) / 2;
        if (res < 0) range_end = (mid + N + 1) / 2 - 1;
        else range_start = (N + mid) / 2 + 1;

        if (range_start == range_end) return range_start;

        // DP-guided search loop for the upper bound
        while (range_start != range_end) {
            guesses_left--;
            int next_target = N - (hcdp[guesses_left - 1] * 2) + (range_end - N) * 2;
            if (next_target - range_end + range_start < 1) 
                next_target = 1 + range_end - range_start;

            int res_loop = Guess(next_target);
            if (res_loop == 0) return (N + next_target) / 2;

            if (res_loop < 0) {
                range_start = (N + next_target) / 2 + 1;
                if (range_start == range_end) return range_start;

                guesses_left--;
                Guess(range_end);
                if (range_end < N) return mirror_search(range_start, range_end, range_end);
            } else {
                range_end = (next_target + N + 1) / 2 - 1;
                return mirror_search(range_start, range_end, next_target);
            }
        }
        return range_start;
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...