import std.conv, std.functional, std.range, std.stdio, std.string; import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons; import core.bitop; class EOFException : Throwable { this() { super("EOF"); } } string[] tokens; string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; } int readInt() { return readToken.to!int; } long readLong() { return readToken.to!long; } real readReal() { return readToken.to!real; } bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } } bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } } int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; } int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); } int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); } uint xrand() { static uint x = 314159265, y = 358979323, z = 846264338, w = 327950288; uint t = x ^ x << 11; x = y; y = z; z = w; return w = w ^ w >> 19 ^ t ^ t >> 8; } enum N = 10; debug { int[] A, B; } int numAsks; int[] Ask(int[] as, int[] bs) { ++numAsks; auto ret = new int[3]; debug { foreach (i; 0 .. N^^2) { ++ret[((A[i] == as[i]) ? 1 : 0) + ((B[i] == bs[i]) ? 1 : 0)]; } } else { foreach (i; 0 .. N^^2) { if (i > 0) write(" "); (as[i] == -1) ? write('?') : write(as[i]); (bs[i] == -1) ? write('?') : write(bs[i]); } writeln(); stdout.flush; foreach (j; 0 .. 3) { ret[j] = readInt(); } } if (ret == [0, 0, N^^2]) { debug { writeln("OK numAsks = ", numAsks); } import core.stdc.stdlib; exit(0); } return ret; } alias Result = Tuple!(int[], "found", int[], "remaining"); Result solveA(int[] xs, int a, int k) { const len = cast(int)(xs.length); assert(0 <= k && k <= len); if (k == 0) { return Result([], xs); } if (k == len) { return Result(xs, []); } auto xss = new int[][2]; foreach (i; 0 .. len) { xss[i % 2] ~= xs[i]; } auto as = new int[N^^2]; auto bs = new int[N^^2]; as[] = -1; bs[] = -1; foreach (x; xss[1]) { as[x] = a; } const res = Ask(as, bs); auto res0 = solveA(xss[0], a, k - res[1]); auto res1 = solveA(xss[1], a, res[1]); return Result(res0.found ~ res1.found, res0.remaining ~ res1.remaining); } Result solveB(int[] xs, int a, int b) { const len = cast(int)(xs.length); assert(0 <= 1 && 1 <= len); if (1 == len) { return Result(xs, []); } auto xss = new int[][3]; foreach (i; 0 .. len) { xss[i % 3] ~= xs[i]; } auto as = new int[N^^2]; auto bs = new int[N^^2]; as[] = -1; bs[] = -1; foreach (x; xss[2]) { as[x] = a; bs[x] = b; } foreach (x; xss[1]) { bs[x] = b; } const res = Ask(as, bs); if (res[2] >= 1) { auto res2 = solveB(xss[2], a, b); return Result(res2.found, xss[0] ~ xss[1] ~ res2.remaining); } else if (res[1] >= 1 + xss[2].length) { auto res1 = solveB(xss[1], a, b); return Result(res1.found, xss[0] ~ res1.remaining ~ xss[2]); } else { auto res0 = solveB(xss[0], a, b); return Result(res0.found, res0.remaining ~ xss[1] ~ xss[2]); } } void main() { debug { A = new int[N^^2]; B = new int[N^^2]; foreach (i; 0 .. N^^2) { A[i] = i / N; B[i] = i % N; } foreach (i; 0 .. N^^2) { const j = cast(int)(xrand() % (i + 1)); swap(A[j], A[i]); swap(B[j], B[i]); } writeln("A = ", A); writeln("B = ", B); } else { readInt(); } auto xs = iota(N^^2).array; auto yss = new int[][N]; foreach (a; 0 .. N) { auto res = solveA(xs, a, N); yss[a] = res.found; xs = res.remaining; } debug { writeln("numAsks = ", numAsks); foreach (a; 0 .. N) { writefln("yss[%s] = %s", a, yss[a]); } } assert(xs == []); auto ansA = new int[N^^2]; auto ansB = new int[N^^2]; ansA[] = -1; ansB[] = -1; foreach (a; 0 .. N) { auto ys = yss[a]; foreach (b; 0 .. N) { auto res = solveB(ys, a, b); assert(res.found.length == 1); ansA[res.found[0]] = a; ansB[res.found[0]] = b; ys = res.remaining; } assert(ys == []); } Ask(ansA, ansB); }