Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.*;
- import java.math.*;
- import java.util.*;
- import java.util.stream.*;
- public class K {
- interface Interactor {
- int getN();
- int query(int[] p);
- int answer(int[] p);
- }
- static final int MAX_Q = 100_000;
- // static final int MAX_Q = 25_000;
- class LocalInteractor implements Interactor {
- int[] p;
- int[][] m;
- int n;
- int qryCnt = 0;
- public LocalInteractor(int n) {
- this.n = n;
- p = new int[n];
- m = new int[n][n];
- for (int i = 0; i < n; i++) {
- int j = rand(0, i);
- p[i] = p[j];
- p[j] = i;
- }
- for (int i = 0; i < n - 1; i++) {
- m[p[i]][p[i + 1]] = m[p[i + 1]][p[i]] = 1;
- }
- }
- boolean isPermutation(int[] a, int n) {
- a = a.clone();
- Arrays.sort(a);
- for (int i = 0; i < n; i++) {
- if (a[i] != i) {
- return false;
- }
- }
- return true;
- }
- @Override
- public int getN() {
- return n;
- }
- @Override
- public int query(int[] q) {
- if (!isPermutation(q, n)) {
- throw new AssertionError("Not a permutation");
- }
- if (++qryCnt > MAX_Q) {
- throw new AssertionError("Too many queries");
- }
- int ret = 0;
- for (int i = 0; i < n - 1; i++) {
- ret += m[q[i]][q[i + 1]];
- }
- return ret;
- }
- @Override
- public int answer(int[] q) {
- if (!isPermutation(q, n)) {
- throw new AssertionError("Not a permutation");
- }
- boolean eq1 = true, eq2 = true;
- for (int i = 0; i < n; i++) {
- eq1 &= p[i] == q[i];
- eq2 &= p[i] == q[n - 1 - i];
- }
- if (!eq1 && !eq2) {
- throw new AssertionError("WA");
- }
- return qryCnt;
- }
- }
- static int arrayLast(int[] arr) {
- return arr[arr.length - 1];
- }
- int solve2(Interactor it) {
- int n = it.getN();
- if (n == 2) {
- return it.answer(new int[] {0, 1});
- }
- ArrayList<int[]> pieces = new ArrayList<>();
- for (int i = 0; i < n; i++) {
- pieces.add(new int[] { i });
- }
- int[][] state = new int[n][n];
- mainCycle: while (pieces.size() > 1) {
- // int newCnt = ((LocalInteractor)it).qryCnt;
- // System.err.println((newCnt - oldCnt) + " qs used");
- // System.err.println(pieces.size() + " pieces left");
- // oldCnt = newCnt;
- Collections.shuffle(pieces, rng);
- randomFlip(pieces);
- int[] qArr = combine(pieces, 0, n);
- int base = it.query(qArr) - (n - pieces.size());
- if (base == 0) {
- markBadPairs(n, state, qArr);
- continue;
- }
- // HARD PART !!!
- // Version 1: just query all the shifts.
- int[] res = new int[pieces.size()];
- res[0] = base;
- for (int i = 1; i < pieces.size(); i++) {
- int newKek1 = arrayLast(pieces.get(Math.floorMod(i - 2, pieces.size())));
- int newKek2 = pieces.get(Math.floorMod(i - 1, pieces.size()))[0];
- int oldKek1 = arrayLast(pieces.get(Math.floorMod(i - 1, pieces.size())));
- int oldKek2 = pieces.get(i)[0];
- if (state[newKek1][newKek2] == -1 && state[oldKek1][oldKek2] == -1) {
- res[i] = res[i - 1];
- continue;
- }
- qArr = combine(pieces, i, n);
- res[i] = it.query(qArr) - (n - pieces.size());
- if (res[i] == 0 && base == 1) {
- pieces.set(i - 1, merge2(pieces.get(i - 1), pieces.get(i), state));
- pieces.remove(i);
- markBadPairs(n, state, qArr);
- continue mainCycle;
- }
- }
- int min = Integer.MAX_VALUE;
- for (int val : res) {
- min = Math.min(min, val);
- }
- int from = 0;
- // res[i] == min => i and (i - 1) are connected
- // res[i] == max => i and (i - 1) are not connected
- while (res[from] == min) {
- from++;
- }
- for (int delta = 0; delta < pieces.size();) {
- int into = (from + delta - 1) % pieces.size();
- while (delta < pieces.size() && res[(from + delta) % pieces.size()] == min) {
- int idx = (from + delta) % pieces.size();
- pieces.set(into, merge2(pieces.get(into), pieces.get(idx), state));
- pieces.set(idx, null);
- delta++;
- }
- delta++;
- }
- for (int i = pieces.size() - 1; i >= 0; i--) {
- if (pieces.get(i) == null) {
- pieces.remove(i);
- }
- }
- }
- return it.answer(pieces.get(0));
- }
- void markBadPairs(int n, int[][] state, int[] qArr) {
- for (int i = 0; i < n - 1; i++) {
- int kek1 = qArr[i];
- int kek2 = qArr[i + 1];
- if (state[kek1][kek2] == 0) {
- state[kek1][kek2] = state[kek2][kek1] = -1;
- }
- }
- }
- int[] merge2(int[] a, int[] b, int[][] state) {
- int[] ret = Arrays.copyOf(a, a.length + b.length);
- System.arraycopy(b, 0, ret, a.length, b.length);
- int kek1 = a[a.length - 1];
- int kek2 = b[0];
- state[kek1][kek2] = state[kek2][kek1] = 1;
- return ret;
- }
- int solve(Interactor it) {
- // int wasted = 0;
- int n = it.getN();
- ArrayList<int[]> pieces = new ArrayList<>();
- for (int i = 0; i < n; i++) {
- pieces.add(new int[] { i });
- }
- // int oldCnt = 0;
- mainCycle: while (pieces.size() > 1) {
- // int newCnt = ((LocalInteractor)it).qryCnt;
- // System.err.println((newCnt - oldCnt) + " qs used");
- // System.err.println(pieces.size() + " pieces left");
- // oldCnt = newCnt;
- Collections.shuffle(pieces, rng);
- randomFlip(pieces);
- int base = it.query(combine(pieces, 0, n)) - (n - pieces.size());
- if (base == 0) {
- // wasted++;
- continue;
- }
- // HARD PART !!!
- // Version 1: just query all the shifts.
- int[] res = new int[pieces.size()];
- res[0] = base;
- for (int i = 1; i < pieces.size(); i++) {
- res[i] = it.query(combine(pieces, i, n)) - (n - pieces.size());
- if (res[i] == 0 && base == 1) {
- pieces.set(i - 1, merge(pieces.get(i - 1), pieces.get(i)));
- pieces.remove(i);
- continue mainCycle;
- }
- }
- int min = Integer.MAX_VALUE;
- for (int val : res) {
- min = Math.min(min, val);
- }
- int from = 0;
- // res[i] == min => i and (i - 1) are connected
- // res[i] == max => i and (i - 1) are not connected
- while (res[from] == min) {
- from++;
- }
- for (int delta = 0; delta < pieces.size();) {
- int into = (from + delta - 1) % pieces.size();
- while (delta < pieces.size() && res[(from + delta) % pieces.size()] == min) {
- int idx = (from + delta) % pieces.size();
- pieces.set(into, merge(pieces.get(into), pieces.get(idx)));
- pieces.set(idx, null);
- delta++;
- }
- delta++;
- }
- for (int i = pieces.size() - 1; i >= 0; i--) {
- if (pieces.get(i) == null) {
- pieces.remove(i);
- }
- }
- }
- // return new int[] { it.answer(pieces.get(0)), wasted };
- return it.answer(pieces.get(0));
- }
- int[] merge(int[] a, int[] b) {
- int[] ret = Arrays.copyOf(a, a.length + b.length);
- System.arraycopy(b, 0, ret, a.length, b.length);
- return ret;
- }
- int[] combine(ArrayList<int[]> lst, int from, int tot) {
- int[] a = new int[tot];
- int ptr = 0;
- for (int i = 0; i < lst.size(); i++) {
- int j = (i + from) % lst.size();
- for (int x : lst.get(j)) {
- a[ptr++] = x;
- }
- }
- return a;
- }
- void randomFlip(ArrayList<int[]> lst) {
- for (int[] arr : lst) {
- if (rng.nextBoolean()) {
- flip(arr);
- }
- }
- }
- void flip(int[] a) {
- for (int i = 0, j = a.length - 1; i < j; i++, j--) {
- int tmp = a[i];
- a[i] = a[j];
- a[j] = tmp;
- }
- }
- void submit() {
- }
- void test() {
- int worst = 0;
- for (int tst = 0;; tst++) {
- // int[] now = solve2(new LocalInteractor(400));
- // if (now[0] > worst) {
- // System.err.println(now[0] + " after " + tst);
- // System.err.println("wasted " + now[1]);
- // worst = now[0];
- // }
- int now = solve2(new LocalInteractor(400));
- if (now > worst) {
- System.err.println(now + " after " + tst);
- worst = now;
- }
- }
- // out.println(solve2(new LocalInteractor(400)));
- }
- void stress() {
- for (int tst = 0;; tst++) {
- if (false) {
- throw new AssertionError();
- }
- System.err.println(tst);
- }
- }
- K() throws IOException {
- is = System.in;
- out = new PrintWriter(System.out);
- // submit();
- // stress();
- test();
- out.close();
- }
- static final Random rng = new Random();
- static final int C = 5;
- static int rand(int l, int r) {
- return l + rng.nextInt(r - l + 1);
- }
- public static void main(String[] args) throws IOException {
- new K();
- }
- private InputStream is;
- PrintWriter out;
- private byte[] buf = new byte[1 << 14];
- private int bufSz = 0, bufPtr = 0;
- private int readByte() {
- if (bufSz == -1)
- throw new RuntimeException("Reading past EOF");
- if (bufPtr >= bufSz) {
- bufPtr = 0;
- try {
- bufSz = is.read(buf);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- if (bufSz <= 0)
- return -1;
- }
- return buf[bufPtr++];
- }
- private boolean isTrash(int c) {
- return c < 33 || c > 126;
- }
- private int skip() {
- int b;
- while ((b = readByte()) != -1 && isTrash(b))
- ;
- return b;
- }
- String nextToken() {
- int b = skip();
- StringBuilder sb = new StringBuilder();
- while (!isTrash(b)) {
- sb.appendCodePoint(b);
- b = readByte();
- }
- return sb.toString();
- }
- String nextString() {
- int b = readByte();
- StringBuilder sb = new StringBuilder();
- while (!isTrash(b) || b == ' ') {
- sb.appendCodePoint(b);
- b = readByte();
- }
- return sb.toString();
- }
- double nextDouble() {
- return Double.parseDouble(nextToken());
- }
- char nextChar() {
- return (char) skip();
- }
- int nextInt() {
- int ret = 0;
- int b = skip();
- if (b != '-' && (b < '0' || b > '9')) {
- throw new InputMismatchException();
- }
- boolean neg = false;
- if (b == '-') {
- neg = true;
- b = readByte();
- }
- while (true) {
- if (b >= '0' && b <= '9') {
- ret = ret * 10 + (b - '0');
- } else {
- if (b != -1 && !isTrash(b)) {
- throw new InputMismatchException();
- }
- return neg ? -ret : ret;
- }
- b = readByte();
- }
- }
- long nextLong() {
- long ret = 0;
- int b = skip();
- if (b != '-' && (b < '0' || b > '9')) {
- throw new InputMismatchException();
- }
- boolean neg = false;
- if (b == '-') {
- neg = true;
- b = readByte();
- }
- while (true) {
- if (b >= '0' && b <= '9') {
- ret = ret * 10 + (b - '0');
- } else {
- if (b != -1 && !isTrash(b)) {
- throw new InputMismatchException();
- }
- return neg ? -ret : ret;
- }
- b = readByte();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement