import java.util.*; public class SequenceGuessing { static final int N = 100000; static final int M = 33333; // track the values that we have committed to in our sequence // cache[i] = j implies i is the jth entry in the sequence // (j = -1 means i is not present, j = 0 implies no commitment has been made) // present.contains(i) implies i is in the sequence // combining these two allows us to find interval and sequence length // for the uncommitted interval containing a guess in log time static int[] cache = new int[N + 1]; static TreeSet present = new TreeSet<>(); static void guess(int x) { if (cache[x] == 0) { // find interval int low = present.lower(x); int high = present.higher(x); // there may very well be a more elegant way to do this, but // most straightforward to code is just to enumerate the cases // see Sequence.java for code that enumerates optimal strategies // for small intervals, from which we can identify patterns // and derive the formulas below switch ((high - low) % 3) { case 0: // sanity check invariant that sequence length is 2/3 interval length // the sanity checks ARE different for each parity assert (cache[high] - cache[low] == (high - low) * 2 / 3); if ((x - low) % 3 == 0) { cache[x] = cache[low] + (x - low) * 2 / 3; present.add(x); } else { // committing to a miss also commits to hitting the adjacent numbers cache[x] = -1; if (cache[x - 1] == 0) { cache[x - 1] = cache[low] + (x - low) * 2 / 3; present.add(x - 1); } else assert (cache[x - 1] == cache[low] + (x - low) * 2 / 3); if (cache[x + 1] == 0) { cache[x + 1] = cache[low] + (x - low) * 2 / 3 + 1; present.add(x + 1); } else assert (cache[x + 1] == cache[low] + (x - low) * 2 / 3 + 1); } break; case 1: // sanity check invariant that sequence length is 2/3 interval length // the sanity checks ARE different for each parity assert (cache[high] - cache[low] == (high - low) * 2 / 3 + 1); if ((x - low) % 3 < 2) { cache[x] = cache[low] + (x - low + 2) * 2 / 3 - 1; present.add(x); } else { // committing to a miss also commits to hitting the adjacent numbers cache[x] = -1; if (cache[x - 1] == 0) { cache[x - 1] = cache[low] + (x - low) * 2 / 3; present.add(x - 1); } else assert (cache[x - 1] == cache[low] + (x - low) * 2 / 3); if (cache[x + 1] == 0) { cache[x + 1] = cache[low] + (x - low) * 2 / 3 + 1; present.add(x + 1); } else assert (cache[x + 1] == cache[low] + (x - low) * 2 / 3 + 1); } break; case 2: // sanity check invariant that sequence length is 2/3 interval length // the sanity checks ARE different for each parity // note: you can also achieve the optimum with a sequence length one higher // than this, but this one is much easier to maintain the invariant for // across all the cases assert (cache[high] - cache[low] == (high - low) * 2 / 3 + 1); if (high - low == 2) { // unfortunate special/base case cache[x] = cache[low] + 1; } else { // committing to a miss also commits to hitting the adjacent numbers cache[x] = -1; if (cache[x - 1] == 0) { cache[x - 1] = cache[low] + (x - low + 1) * 2 / 3 - 1; present.add(x - 1); } else assert (cache[x - 1] == cache[low] + (x - low + 1) * 2 / 3 - 1); if (cache[x + 1] == 0) { cache[x + 1] = cache[low] + (x - low + 1) * 2 / 3; present.add(x + 1); } else assert (cache[x + 1] == cache[low] + (x - low + 1) * 2 / 3); } break; } } } // overall strategy: // assert that the sequence is missing exactly as many numbers as // the target number of misses, so 1/3 missing and 2/3 present // every guess for a number we haven't committed to effectively splits // the sequence into two pieces; we want to maintain the ratio // of missing numbers in each piece // inspection of small interval strategies reveals the details on // how to do so for every possible guess public static void main(String[] args) { assert(N % 10 == 0); assert(N / 3 == M); cache[0] = 1; cache[N] = N * 2 / 3 + 2; // 66668 when N = 100000 as per the problem statement System.out.println(cache[N]); present.add(0); present.add(N); Scanner s = new Scanner(System.in); while (true) { int x = s.nextInt(); if (x == -1) break; guess(x); System.out.println(cache[x]); } ArrayList all = new ArrayList<>(); for (int i = 1; i < N; i++) all.add(i); // sanity check, helped with finding bugs // Collections.shuffle(all); for (int i : all) guess(i); // fill in the rest of the sequence for (int num : present) System.out.println(num); } }