Submission
Status:
(PPPPPPPPPPPPPP-)(P-SSSSSS)(PPPPPPPPPP)(-SSSSSSSSS)(-SSSSSSSSS)(-SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS)
Subtask/Task Score:
{0/3}{0/7}{12/12}{0/17}{0/21}{0/40}
Score: 12
User: Pera
Problemset: รถไฟตู้เสบียง (Dining Car)
Language: cpp
Time: 0.003 second
Submitted On: 2026-09-10 10:35:57
#include <bits/stdc++.h>
#include "dining_car.h"
using namespace std;
static map<int, int> memo_g;
static int ask_compare(int p, int q) {
if (p == q) return 0;
return compare_cars(p, q);
}
static int get_g(int x, int N) {
if (x <= 0) return 1;
if (x >= N) return -1;
auto it = memo_g.find(x);
if (it != memo_g.end()) return it->second;
return memo_g[x] = ask_compare(x, x + 1);
}
pair<int, int> locate_dining_cars(int N) {
memo_g.clear();
// Step 1: Find one dining car X in at most 30 queries
int L = 0, R = N;
while (R - L > 1) {
int mid = L + (R - L) / 2;
int res = get_g(mid, N);
if (res >= 0) {
L = mid;
} else {
R = mid;
}
}
int X = R; // X is either A or B
// Step 2: Determine whether X is A or B in at most 1 query
bool is_A = false;
if (X == 1) {
is_A = true;
} else if (X == N) {
is_A = false;
} else {
if (X - 1 <= N - X) {
int res = ask_compare(1, 2 * X - 1);
is_A = (res != -1);
} else {
int res = ask_compare(N, 2 * X - N);
is_A = (res == -1);
}
}
// Step 3: Find the other dining car
if (is_A) {
int A = X;
int low = A, high = N;
while (high - low > 1) {
int target = low + (high - low) / 2;
int mid = target;
// Check if a query inside (low, high) is already cached
auto it = memo_g.upper_bound(low);
if (it != memo_g.end() && it->first < high) {
int best_p = it->first;
int best_diff = abs(best_p - target);
while (it != memo_g.end() && it->first < high) {
if (abs(it->first - target) < best_diff) {
best_diff = abs(it->first - target);
best_p = it->first;
}
++it;
}
// Reuse cached point if it reasonably bifurcates the search interval
if (best_diff <= (high - low) / 4) {
mid = best_p;
}
}
int res = get_g(mid, N);
if (res == 0) {
if (mid == A) {
return {A, A + 1};
} else {
int B = 2 * mid + 1 - A;
return {A, B};
}
} else if (res > 0) {
low = mid;
} else {
high = mid;
}
}
return {A, high};
} else {
int B = X;
int low = 0, high = B;
while (high - low > 1) {
int target = low + (high - low) / 2;
int mid = target;
auto it = memo_g.upper_bound(low);
if (it != memo_g.end() && it->first < high) {
int best_p = it->first;
int best_diff = abs(best_p - target);
while (it != memo_g.end() && it->first < high) {
if (abs(it->first - target) < best_diff) {
best_diff = abs(it->first - target);
best_p = it->first;
}
++it;
}
if (best_diff <= (high - low) / 4) {
mid = best_p;
}
}
int res = get_g(mid, N);
if (res == 0) {
if (mid == B - 1) {
return {B - 1, B};
} else {
int A = 2 * mid + 1 - B;
return {A, B};
}
} else if (res > 0) {
low = mid;
} else {
high = mid;
}
}
return {high, B};
}
}