import java.util.*; import java.io.*; public class Validator { static final int N = 100000; static final int M = 33333; static final int MUST_BE_PRESENT = -2; // cache[x] == 0 means no information given // cache[x] == -2 (MUST BE PRESENT) means it must be present (adjacent to miss) // cache[x] == -1 means it is definitely missing // cache[x] >= 1 means it is that index static int[] cache = new int[N + 1]; // given[x] is the response the contestant gave to x (-1, or 1 through K) // given[x] == 0 means no response was given static int[] given = new int[N + 1]; // guessed[x] is true if the player has guessed x, and false otherwise static boolean[] guessed = new boolean[N + 1]; static ArrayList order = new ArrayList<>(); static TreeSet present = new TreeSet<>(); static int misses = 0; static int idx = 0; static int numGuessesRemaining; static int tryReadInt(Scanner sc, int low, int high, boolean shouldBail) { try { int ret = Integer.parseInt(sc.next()); if(ret < low || ret > high) throw new RuntimeException("illegal value"); return ret; } catch(Exception e) { e.printStackTrace(); // prints to stderr the stack trace just so we have logging if(shouldBail) bail(); else System.exit(43); return -39; // never reached, for compiler } catch(Throwable t) { t.printStackTrace(); // prints to stderr the stack trace just so we have logging System.exit(43); // exit immediately, any throwable here is likely unrecoverable return -40; // never reached, for compiler } } static int nextGuess() { if(numGuessesRemaining <= 0 || misses == M) return -1; int ans = order.get(idx); while (guessed[ans] && idx < N) { ans = order.get(++idx); } if (idx == N && guessed[ans]) return -1; return ans; } static void bail() { System.out.println(-1); System.exit(43); } static void guessAndValidate(Scanner s, int guess, int K) { if(misses == M) throw new RuntimeException("not allowed to guess"); guessed[guess] = true; System.out.println(guess); numGuessesRemaining--; int ans = tryReadInt(s, -1, K, true); if(ans == 0) bail(); // ans 0 is never legal given[guess] = ans; if (cache[guess] == MUST_BE_PRESENT && ans < 1) bail(); if (cache[guess] != 0 && cache[guess] >= -1 && cache[guess] != ans) bail(); if (ans == -1) { if (guess == 0 || guess == N) bail(); if (cache[guess - 1] == 0) cache[guess - 1] = MUST_BE_PRESENT; if (cache[guess + 1] == 0) cache[guess + 1] = MUST_BE_PRESENT; misses++; } else { // ans >= 1 here if (guess > 0 && cache[guess - 1] > 0 && ans != cache[guess - 1] + 1) bail(); if (guess > 1 && cache[guess - 1] == -1 && cache[guess - 2] > 0 && ans != cache[guess - 2] + 1) bail(); if (guess < N && cache[guess + 1] > 0 && ans != cache[guess + 1] - 1) bail(); if (guess < N - 1 && cache[guess + 1] == -1 && cache[guess + 2] > 0 && ans != cache[guess + 2] - 1) bail(); present.add(guess); } cache[guess] = ans; } static void processInterval(Scanner s, int before, int after, int K) { int length = after - before - 1; if (length == 0) return; int present = cache[after] - cache[before] - 1; int missing = length - present; if (missing < (length + 4) / 3) return; int cursor = before + 2; while (cursor < after) { guessAndValidate(s, cursor, K); if (cache[cursor] == -1) { guessAndValidate(s, cursor - 1, K); if (cache[cursor - 1] != cache[cursor - 2] + 1) bail(); if (cursor + 1 == after) { cursor += 2; } else { guessAndValidate(s, cursor + 1, K); if (cache[cursor + 1] != cache[cursor - 1] + 1) bail(); cursor += 3; } } else if (cache[cursor] == cache[cursor - 2] + 2) { guessAndValidate(s, cursor - 1, K); if (cache[cursor - 1] != cache[cursor - 2] + 1) bail(); cursor += 2; } else if (cache[cursor] == cache[cursor - 2] + 1) { cache[cursor - 1] = -1; guessed[cursor - 1] = true; cursor += 2; } else { bail(); } } if (cache[after - 2] == cache[after] - 2 || cache[after - 2] == -1) { if (!guessed[after - 1]) guessAndValidate(s, after - 1, K); if (cache[after - 1] != cache[after] - 1) bail(); } else if (cache[after - 2] == cache[after] - 1) { cache[after - 1] = -1; guessed[after - 1] = true; } else { bail(); } } public static void main(String[] args) throws IOException { Scanner s = new Scanner(System.in); final int K = tryReadInt(s, 2, N+1, true); Scanner fin = new Scanner(new File(args[0])); String strategy = fin.next(); if(strategy.startsWith("fixed-modulo")) { int modulo = fin.nextInt(); int[] moduli = new int[modulo]; for(int i = 0; i < modulo; i++) moduli[i] = fin.nextInt(); String sort = fin.next(); int seed = fin.nextInt(); numGuessesRemaining = fin.nextInt(); Random r = new Random(seed); fin.close(); for(int cmod: moduli) { ArrayList temp = new ArrayList<>(); for(int a = cmod; a <= N; a += modulo) { temp.add(a); } if(sort.equals("inc")); else if(sort.equals("dec")) Collections.reverse(temp); else if(sort.equals("rand")) Collections.shuffle(temp, r); for(int out: temp) order.add(out); } int guess = nextGuess(); while (guess != -1) { guessAndValidate(s, guess, K); if (cache[guess] == -1) { if (misses == M) break; // if (cache[guess - 1] == MUST_BE_PRESENT) guessAndValidate(s, guess - 1, K); // if (cache[guess + 1] == MUST_BE_PRESENT) guessAndValidate(s, guess + 1, K); // IMPORTANT: skip these for fixed guess order! // if (guess > 1) processInterval(s, present.lower(guess - 1), guess - 1, K); // if (guess < N - 1) processInterval(s, guess + 1, present.higher(guess + 1), K); } else { // processInterval(s, present.lower(guess), guess, K); // processInterval(s, guess, present.higher(guess), K); } guess = nextGuess(); } } else if(strategy.equals("smart")) { int seed = fin.nextInt(); numGuessesRemaining = fin.nextInt(); fin.close(); Random r = new Random(seed); for (int i = 0; i <= N; i++) order.add(i); Collections.shuffle(order, r); if (K > N - M + 1) { // too many numbers, can just win by guessing every single number for (int i = 0; i <= N; i++) { guessAndValidate(s, i, K); } System.exit(43); } guessAndValidate(s, 0, K); if (cache[0] != 1) System.exit(43); guessAndValidate(s, N, K); if (cache[N] != K) System.exit(43); processInterval(s, 0, N, K); int guess = nextGuess(); while (guess != -1) { guessAndValidate(s, guess, K); if (cache[guess] == -1) { if (misses == M) break; if (cache[guess - 1] == MUST_BE_PRESENT) guessAndValidate(s, guess - 1, K); if (cache[guess + 1] == MUST_BE_PRESENT) guessAndValidate(s, guess + 1, K); if (guess > 1) processInterval(s, present.lower(guess - 1), guess - 1, K); if (guess < N - 1) processInterval(s, guess + 1, present.higher(guess + 1), K); } else { processInterval(s, present.lower(guess), guess, K); processInterval(s, guess, present.higher(guess), K); } guess = nextGuess(); } } else { fin.close(); throw new RuntimeException("unexpected strategy of " + strategy); } if(misses > M) { throw new RuntimeException("judge should have never had more than M misses"); } // from this point onward, misses <= M System.out.println(-1); boolean allGuessed = true; for(int i = 0; i <= N; i++) { if(!guessed[i]) allGuessed = false; } if(allGuessed && misses < M) { System.exit(43); } // from this point onward, misses == M int prev = -1; int[] vals = new int[K]; for (int i = 0; i < K; i++) { vals[i] = tryReadInt(s, 0, N, false); // check that number was not explicitly excluded if (given[vals[i]] == -1) System.exit(43); // if number was included, make sure rank matches if (given[vals[i]] > 0 && given[vals[i]] != i + 1) System.exit(43); // confirm difference is 1 or 2 if (vals[i] - prev > 2 || vals[i] - prev < 1) System.exit(43); prev = vals[i]; } // confirm start and end if(vals[0] != 0 || vals[K-1] != N) System.exit(43); // sanity check that included numbers are explicitly included for(int i = 0; i <= N; i++) { if(given[i] >= 1 && given[i] <= K) { if(vals[given[i] - 1] != i) System.exit(43); } } try { // look for additional output s.next(); // there was additional output, so WA System.exit(43); } catch(NoSuchElementException e) { // there was no additional output, AC! System.exit(42); } catch(Throwable t) { // instead of automatically WAing, we raise an exception explicitly here // for investigation System.err.println("unexpected throwable: " + t); t.printStackTrace(); // something unexpected happened!? throw new RuntimeException("unexpected alternate exception"); } // should never get here either... throw new RuntimeException("did not exit properly"); } }