Submission #1256260

#TimeUsernameProblemLanguageResultExecution timeMemory
1256260nibertSouvenirs (IOI25_souvenirs)C++20
0 / 100
12 ms412 KiB
#include <bits/stdc++.h> using namespace std; // Provided by the grader. extern pair<vector<int>, long long> transaction(long long M); static const long long INF = (1LL<<62); void buy_souvenirs(int N, long long P0) { vector<long long> P(N); P[0] = P0; // Track how many of each type we've already bought (counts all queries). vector<long long> bought(N, 0); auto call = [&](long long M)->int { auto [L, R] = transaction(M); for (int t: L) bought[t]++; // count all purchases if (L.empty()) return N; // "none" return L[0]; // first bought index }; // Helper: do a safe call that buys at most one item when it hits index k. auto call_capped = [&](long long M, int k)->int { // If we know P[k+1], cap M so that after buying k, remainder < P[k+1]. if (k+1 < N && P[k+1] > 0) { // Ensure M <= P[k] + P[k+1] - 1 when searching "in the zone". // We'll clamp downwards if needed (P[k] might still be unknown during search; // in that case we can't cap by it yet and just use M). if (P[k] > 0) { long long cap = P[k] + P[k+1] - 1; if (cap < M) M = cap; } } return call(M); }; // ----- Phase A: recover all P[k], k = N-1..1 ----- // We keep dynamic search bounds per k: [lo_k, hi_k] such that P[k] in [lo_k, hi_k]. vector<long long> lo(N, 1), hi(N, P0-1); // Unknowns are P[1..N-1]. We'll find from bottom to top to learn P[k+1] first. // For k=N-1 initially we don't know hi; it's P[N-2]-1, but we can start with P0-1 safely. // We will progressively tighten using known neighbors. for (int k = N-1; k >= 1; --k) { // If we already know next and prev thresholds, shrink bounds. if (k+1 < N && P[k+1] > 0) lo[k] = max(lo[k], P[k+1] + 1); if (k-1 >= 1 && P[k-1] > 0) hi[k] = min(hi[k], P[k-1] - 1); // Binary search minimal M with f(M) <= k long long L = lo[k], R = hi[k]; // Guard: ensure L<=R (it will be, but be safe) if (L < 1) L = 1; if (R >= P0) R = P0-1; // We’ll use standard binary search. To reduce extra buys, // when we detect f(M)==k we try to keep M <= P[k]+P[k+1]-1 once P[k] is known // (not known on first hits; it's okay). while (L < R) { long long mid = L + ((R - L) >> 1); int first = call(mid); // single call; counts purchases if (first <= k) { R = mid; } else { L = mid + 1; } } // L=R is the minimal M where first<=k; this equals P[k]. // Do one more call at M=L to also capture the remainder if you want (not necessary). // But we may have already called it as last 'mid'; if not, call it now. // We need the value P[k], not the items from the call. To avoid another call, // just set P[k]=L directly; correctness: by the monotonicity argument, the minimal M is exactly P[k]. P[k] = L; } // ----- Phase B: top-up to exact targets with few calls ----- // Target: T[0]=0, T[i]=i for i>=1 for (int i = 1; i < N; ++i) { long long need = i - bought[i]; while (need > 0) { // Buy exactly one item of type i. long long padBelow = (i+1 < N ? P[i+1]-1 : (P0-1 - P[i])); // safe tail pad if (padBelow < 0) padBelow = 0; long long M = P[i] + min(padBelow, P0-1 - P[i]); // ensure < P0 // Edge case: if M < P[N-1] (very tiny), bump to P[N-1] if (M < P[N-1]) M = P[N-1]; auto [L, R] = transaction(M); for (int t: L) bought[t]++; // Assert we bought exactly type i // (In a contest, you can assert and abort; here we just trust the construction.) need--; } } }
#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...