結果

問題 No.3496 協力カード当て
コンテスト
ユーザー yuki2006
提出日時 2026-04-14 20:57:04
言語 Java
(openjdk 25.0.2)
コンパイル:
javac -encoding UTF8 _filename_
実行:
java -ea -Xmx700m -Xss256M -DONLINE_JUDGE=true _class_
結果
AC  
実行時間 245 ms / 2,000 ms
コード長 4,351 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,517 ms
コンパイル使用メモリ 84,504 KB
実行使用メモリ 68,080 KB
スコア 132
平均クエリ数 40.00
最終ジャッジ日時 2026-04-14 23:50:23
合計ジャッジ時間 15,868 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge1_0
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 16
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

 import java.util.*;
  import java.io.*;

  public class Main {
      static long comb(int n, int r) {
          if (r < 0 || n < 0 || r > n) return 0;
          if (r == 0) return 1;
          if (r > n - r) r = n - r;
          long res = 1;
          for (int i = 0; i < r; i++) res = res * (n - i) / (i + 1);
          return res;
      }

      static long rankMultiset(int[] c, int N, int M) {
          long r = 0;
          int rem = N;
          for (int i = 0; i < M; i++) {
              for (int v = 0; v < c[i]; v++)
                  r += comb(rem - v + M - i - 2, M - i - 2);
              rem -= c[i];
          }
          return r;
      }

      static int[] unrankMultiset(long idx, int N, int M) {
          int[] c = new int[M];
          int rem = N;
          for (int i = 0; i < M; i++) {
              if (i == M - 1) { c[i] = rem; break; }
              for (int v = 0; v <= rem; v++) {
                  long cnt = comb(rem - v + M - i - 2, M - i - 2);
                  if (idx < cnt) { c[i] = v; rem -= v; break; }
                  idx -= cnt;
              }
          }
          return c;
      }

      static int[] encodePerm(long idx, int M) {
          int[] perm = new int[M];
          List<Integer> avail = new ArrayList<>();
          for (int i = 1; i <= M; i++) avail.add(i);
          int p = 0;
          for (int i = M; i >= 1; i--) {
              long f = 1;
              for (int j = 1; j < i; j++) f *= j;
              int q = (int) (idx / f);
              idx %= f;
              perm[p++] = avail.get(q);
              avail.remove(q);
          }
          return perm;
      }

      static long decodePerm(int[] perm, int M) {
          long idx = 0;
          List<Integer> avail = new ArrayList<>();
          for (int i = 1; i <= M; i++) avail.add(i);
          for (int i = M; i >= 1; i--) {
              long f = 1;
              for (int j = 1; j < i; j++) f *= j;
              int q = avail.indexOf(perm[M - i]);
              idx += (long) q * f;
              avail.remove(q);
          }
          return idx;
      }

      public static void main(String[] args) {
          Scanner sc = new Scanner(System.in);
          PrintWriter out = new PrintWriter(new BufferedWriter(new
  OutputStreamWriter(System.out)));

          int id = sc.nextInt();
          int N = sc.nextInt();
          int M = sc.nextInt();

          int[] myCount = new int[M];
          for (int i = 0; i < N; i++) {
              int v = sc.nextInt();
              myCount[v - 1]++;
          }

          int[] qorder = encodePerm(rankMultiset(myCount, N, M), M);

          int qpos = 0;
          List<Integer> oppQueries = new ArrayList<>();
          int[] total = new int[20];
          boolean afterWait = false;

          while (sc.hasNext()) {
              String cmd = sc.next();
              if (cmd.equals("END")) {
                  sc.nextInt();
                  break;
              } else if (cmd.equals("TURN")) {
                  afterWait = false;
                  if (qpos < M) {
                      out.println("ASK " + qorder[qpos++]);
                      out.flush();
                  } else {
                      int[] oppArr = new int[oppQueries.size()];
                      for (int i = 0; i < oppArr.length; i++) oppArr[i] = oppQueries.get(i);
                      int[] oppCount = unrankMultiset(decodePerm(oppArr, M), N, M);
                      StringBuilder sb = new StringBuilder("GUESS");
                      for (int v = 0; v < M; v++) {
                          int c = total[v + 1] - myCount[v] - oppCount[v];
                          for (int j = 0; j < c; j++) sb.append(' ').append(v + 1);
                      }
                      out.println(sb);
                      out.flush();
                  }
              } else if (cmd.equals("WAIT")) {
                  afterWait = true;
              } else if (cmd.equals("COUNT")) {
                  int x = sc.nextInt();
                  int k = sc.nextInt();
                  total[x] = k;
                  if (afterWait) {
                      oppQueries.add(x);
                      afterWait = false;
                  }
              } else if (cmd.equals("GUESSED")) {
                  sc.nextInt();
                  sc.nextInt();
              }
          }
      }
  }
0