結果

問題 No.2907 Business Revealing Dora Tiles
ユーザー 👑 amentorimaruamentorimaru
提出日時 2024-09-17 00:31:03
言語 C++23
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 202 ms / 3,000 ms
コード長 3,831 bytes
コンパイル時間 12,360 ms
コンパイル使用メモリ 188,572 KB
実行使用メモリ 6,944 KB
最終ジャッジ日時 2024-09-23 13:06:19
合計ジャッジ時間 21,684 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
6,816 KB
testcase_01 AC 3 ms
6,812 KB
testcase_02 AC 3 ms
6,944 KB
testcase_03 AC 46 ms
6,940 KB
testcase_04 AC 31 ms
6,944 KB
testcase_05 AC 5 ms
6,940 KB
testcase_06 AC 4 ms
6,944 KB
testcase_07 AC 21 ms
6,940 KB
testcase_08 AC 18 ms
6,944 KB
testcase_09 AC 4 ms
6,944 KB
testcase_10 AC 3 ms
6,940 KB
testcase_11 AC 32 ms
6,940 KB
testcase_12 AC 3 ms
6,940 KB
testcase_13 AC 4 ms
6,944 KB
testcase_14 AC 4 ms
6,940 KB
testcase_15 AC 4 ms
6,940 KB
testcase_16 AC 4 ms
6,940 KB
testcase_17 AC 3 ms
6,944 KB
testcase_18 AC 7 ms
6,940 KB
testcase_19 AC 4 ms
6,940 KB
testcase_20 AC 3 ms
6,940 KB
testcase_21 AC 32 ms
6,944 KB
testcase_22 AC 6 ms
6,940 KB
testcase_23 AC 53 ms
6,944 KB
testcase_24 AC 81 ms
6,940 KB
testcase_25 AC 79 ms
6,940 KB
testcase_26 AC 80 ms
6,944 KB
testcase_27 AC 80 ms
6,940 KB
testcase_28 AC 80 ms
6,940 KB
testcase_29 AC 113 ms
6,944 KB
testcase_30 AC 79 ms
6,944 KB
testcase_31 AC 80 ms
6,944 KB
testcase_32 AC 80 ms
6,940 KB
testcase_33 AC 79 ms
6,940 KB
testcase_34 AC 79 ms
6,944 KB
testcase_35 AC 111 ms
6,944 KB
testcase_36 AC 80 ms
6,940 KB
testcase_37 AC 79 ms
6,940 KB
testcase_38 AC 79 ms
6,940 KB
testcase_39 AC 79 ms
6,940 KB
testcase_40 AC 79 ms
6,940 KB
testcase_41 AC 96 ms
6,944 KB
testcase_42 AC 79 ms
6,944 KB
testcase_43 AC 111 ms
6,940 KB
testcase_44 AC 123 ms
6,940 KB
testcase_45 AC 197 ms
6,944 KB
testcase_46 AC 106 ms
6,940 KB
testcase_47 AC 69 ms
6,940 KB
testcase_48 AC 74 ms
6,944 KB
testcase_49 AC 202 ms
6,940 KB
testcase_50 AC 170 ms
6,944 KB
testcase_51 AC 14 ms
6,940 KB
testcase_52 AC 80 ms
6,944 KB
testcase_53 AC 103 ms
6,940 KB
testcase_54 AC 52 ms
6,944 KB
testcase_55 AC 103 ms
6,940 KB
testcase_56 AC 104 ms
6,944 KB
testcase_57 AC 105 ms
6,944 KB
testcase_58 AC 100 ms
6,940 KB
testcase_59 AC 97 ms
6,940 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <atcoder/all>

using namespace std;
using u64 = unsigned long long;
using mint = atcoder::modint998244353;

u64 pre_prod[256][256] = { 0 };
u64 pre_inv[256] = { 0 };

u64 nim_product(u64 a, u64 b, int d = 6) noexcept {
  if (min(a, b) <= 1) return a * b;
  if (a < 256 && b < 256 && pre_prod[a][b]) { return pre_prod[a][b]; }

  d--;
  u64 d_pow = 1ULL << d;
  u64 d_pow_pow = 1ULL << d_pow;
  if (a < d_pow_pow && b < d_pow_pow) {
    return nim_product(a, b, d);
  }

  u64 au = a >> d_pow;
  u64 al = a - (au << d_pow);
  u64 bu = b >> d_pow;
  u64 bl = b - (bu << d_pow);
  u64 aubu = nim_product(au, bu, d);
  u64 albu = nim_product(al, bu, d);
  u64 aubl = nim_product(au, bl, d);
  u64 albl = nim_product(al, bl, d);

  u64 res = ((aubu ^ aubl ^ albu) << d_pow) ^ (nim_product(aubu, d_pow_pow / 2, d)) ^ (albl);

  if (a < 256 && b < 256)
    pre_prod[a][b] = pre_prod[b][a] = res;
  return res;
}

u64 nim_product_inv(u64 a, int d = 6) {
  if (a < 256)
    return pre_inv[a];
  d--;
  u64 d_pow = 1 << d;
  u64 au = a >> d_pow;
  u64 al = a - (au << d_pow);
  u64 half_inv = nim_product_inv(nim_product(au ^ al, al, d) ^ nim_product(nim_product(au, au, d), 1ULL << (d_pow - 1)), d);
  return (nim_product(half_inv, au, d) << d_pow) ^ nim_product(half_inv, au ^ al, d);
}


int main() {
  // precalc
  for (int a = 1; a < 256; a++) {
    for (int b = a; b < 256; b++) {
      u64 c = nim_product(a, b);
      if (c == 1) {
        pre_inv[a] = b;
        pre_inv[b] = a;
      }
    }
  }

  int n, t;
  cin >> n >> t;
  vector h(t, vector<u64>(n));
  for (int r = 0; r < t; r++) {
    for (int c = 0; c < n; c++) {
      cin >> h[r][c];
      h[r][c]--;
    }
  }

  // 通常の掃き出し(pop_backの都合上、右から)
  vector<int> use(t, -1);
  for (int c0 = n - 1; c0 >= 0; c0--) {
    int r0 = -1;
    for (int r = 0; r < t; r++) {
      if (h[r][c0] == 0 || use[r] != -1)
        continue;
      use[r] = c0;
      r0 = r;
      break;
    }
    if (r0 == -1)
      continue;
    u64 inv = nim_product_inv(h[r0][c0]);
    for (auto& v : h[r0])
      v = nim_product(v, inv);
    for (int r = 0; r < t; r++) {
      if (r == r0)
        continue;
      for (int c = 0; c < n; c++) {
        h[r][c] ^= nim_product(h[r0][c], h[r][c0]);
      }
    }
  }
  
  // 正方行列の生成
  vector base_a(n, vector<u64>(n));
  for (int i = 0; i < t; i++) {
    if (use[i] != -1) {
      base_a[use[i]] = h[i];
    }
  }

  mint ans = 0;
  mint mul = mint(2).pow(64);

  auto dfs = [&](auto self, vector<vector<u64>>& a, mint add, int pop, int column) -> void {
    if (column < 0) {
      ans += pop % 2 ? -add : add;
      return;
    }

    // この列を消さない
    auto a0 = a;
    mint add0 = add;
    if (a0.back().back() == 0)
      add0 *= mul;
    a0.pop_back();
    for (auto& r : a0)
      r.pop_back();
    self(self, a0, add0, pop, column - 1);


    // この列を消す
    auto a1 = a;
    for (auto& r : a1)
      r.pop_back();
    // 別の列の要素があるなら、そこを掃き出す(O(column^2))
    for (int c0 = a1.back().size() - 1; c0 >= 0; c0--) {
      if (a1.back()[c0]) {
        u64 ainv = nim_product_inv(a1.back()[c0]);
        for (auto& v : a1.back())
          v = nim_product(v, ainv);
        for (int r = 0; r < a1.size(); r++) {
          for (int c = 0; c < a1[r].size(); c++) {            
            if (r == c0) {
              if (a1[r][c0] != a1.back()[c0])
                a1[r][c] ^= a1.back()[c];
            }
            else {
              a1[r][c] ^= nim_product(a1.back()[c], a1[r][c0]);
            }
          }
        }
        break;
      }
    }
    a1.pop_back();
    self(self, a1, add, pop + 1, column - 1);
    return;
  };
  dfs(dfs, base_a, 1, 0, n - 1);
  cout << ans.val() << endl;
}
0