結果

問題 No.3047 Verification of Sorting Network
ユーザー 👑 Mizar
提出日時 2025-02-12 19:45:29
言語 TypeScript
(5.7.2)
結果
AC  
実行時間 848 ms / 2,000 ms
コード長 4,261 bytes
コンパイル時間 8,240 ms
コンパイル使用メモリ 266,704 KB
実行使用メモリ 59,676 KB
最終ジャッジ日時 2025-03-05 20:41:00
合計ジャッジ時間 47,817 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 61
権限があれば一括ダウンロードができます

ソースコード

diff #

{
const MaxT: number = 1000;
const MaxN: number = 27;
const MaxCost: number = 1e8;

type Result<Success, Error> = Ok<Success> | Err<Error>;
type Ok<Success> = { tag: "Yes"; data: Success };
type Err<Error> = { tag: "No"; data: Error };
const Ok = <Success>(data: Success): Ok<Success> => ({ tag: "Yes", data });
const Err = <Error>(data: Error): Err<Error> => ({ tag: "No", data });

function isSortingNetwork(
  n: number,
  cmps: [number, number][]
): Result<boolean[], boolean[]> {
  // initial state: all elements are unknown
  const stack: [number, number, number][] = [
    [(1 << n) - 1, (1 << n) - 1, 0],
  ];
  const unused: boolean[] = Array(cmps.length).fill(true);
  let unsorted_i = 0;
  const m = cmps.length;

  // branch loop
  a: while (stack.length > 0) {
    // get branch state
    // z: 0 bitwise state
    // o: 1 bitwise states
    // i: index of cmps
    let [z, o, i] = stack.pop()!;

    // CEs (compare/exchange elements) loop
    while (i < m) {
      // get next comparison
      let [a, b] = cmps[i++];
      if (((o >> a) & 1) == 0 || ((z >> b) & 1) == 0) {
        // (0, 0) or (1, 1) or (0, 1) or (0, ?) or (?, 1), no operation, continue to next CE
      } else if (((z >> a) & 1) == 1 && ((o >> b) & 1) == 1) {
        unused[i - 1] = false;
        // both elements are unknown
        // branch into (0, 0) and (?, 1)
        // copy state for (0, 0) new branch
        // set state for (?, 1) current branch
        let qz = z;
        let qo = (o ^ (1 << a) ^ (1 << b));
        z ^= (1 << b);
        // if 'qz,qo' not sorted, push branch into stack
        if ((qo & (qz >> 1)) != 0) {
          stack.push([qz, qo, i]);
        }
        // z,o is sorted, continue to next branch
        if ((o & (z >> 1)) == 0) {
          continue a;
        }
      } else {
        unused[i - 1] = false;
        // if (1, 0) or (?, 0) or (1, ?), swap elements
        let xz = (((z >> a) ^ (z >> b)) & 1);
        let xo = (((o >> a) ^ (o >> b)) & 1);
        z ^= ((xz << a) | (xz << b));
        o ^= ((xo << a) | (xo << b));
        // z,o is sorted, continue to next branch
        if ((o & (z >> 1)) == 0) {
          continue a;
        }
      }
    }
    // if z,o is not sorted
    unsorted_i |= (o & (z >> 1));
  }

  if (unsorted_i != 0) {
    const unsorted: boolean[] = Array.from({ length: n - 1 }, (_, i) => ((unsorted_i >> i) & 1) != 0);
    return Err(unsorted);
  }
  // if p is sorted for all branches
  return Ok(unused);
}

function main(): void {
  const input: string[] = require("fs")
    .readFileSync("/dev/stdin", "utf8")
    .split("\n");
  let index = 0;

  const t = parseInt(input[index++], 10);
  if (t > MaxT) throw new Error(`t must be <= ${MaxT}`);

  // phi = (1 + sqrt(5)) / 2 : golden ratio
  const phi = Math.sqrt(1.25) + 0.5;
  // testcases cost <= 1e8
  let cost = 0.0;

  for (let i = 0; i < t; ++i) {
    const [n, m] = input[index++].split(" ").map((str) => parseInt(str, 10));
    if (!(2 <= n && n <= MaxN && 1 <= m && m <= (n * (n - 1)) / 2))
      throw new Error("Invalid n or m");
    cost += m * Math.pow(phi, n);
    if (cost > MaxCost) throw new Error(`Cost must be <= ${MaxCost}`);

    // 1-indexed to 0-indexed
    const va: number[] = input[index++].split(" ").map((str) => parseInt(str, 10) - 1);
    const vb: number[] = input[index++].split(" ").map((str) => parseInt(str, 10) - 1);
    const cmps: [number, number][] = va.map((a, i) => [a, vb[i]]);
    if (cmps.length !== m) throw new Error("Invalid cmps length");
    if (cmps.some(([a, b]) => !(0 <= a && a < b && b < n))) throw new Error("Invalid a or b");

    const { data, tag } = isSortingNetwork(n, cmps);
    console.log(tag);
    if (tag === "Yes") {
      if (data.length !== m) throw new Error("Invalid data length");
      console.log(data.filter((x) => x).length);
      console.log(
        data
          .map((x, i) => (x ? i + 1 : 0))
          .filter((x) => x)
          .join(" ")
      );
    } else if (tag === "No") {
      if (data.length !== n - 1) throw new Error("Invalid data length");
      console.log(data.filter((x) => x).length);
      console.log(
        data
          .map((x, i) => (x ? i + 1 : 0))
          .filter((x) => x)
          .join(" ")
      );
    }
  }
}

main();
}
0