結果
問題 | No.2505 matriX cOnstRuction |
ユーザー |
|
提出日時 | 2023-07-27 23:59:41 |
言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 4,431 bytes |
コンパイル時間 | 922 ms |
コンパイル使用メモリ | 80,572 KB |
実行使用メモリ | 53,376 KB |
最終ジャッジ日時 | 2024-10-06 17:50:18 |
合計ジャッジ時間 | 5,030 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 34 WA * 30 |
ソースコード
// WA#include <array>#include <cstdint>#include <iostream>#include <vector>using Value = uint32_t;using Weight = int64_t;// nm の最大値constexpr size_t MAX_NM = 50000;constexpr size_t BIT_NUM = 30;namespace binary_trie {// ノードは整数 ID で管理using Node = size_t;constexpr Node null_node = ~size_t(0);// Binary Trie のノード数の上界constexpr size_t MAX_NODE_NUM = 3 * (MAX_NM + 1) * BIT_NUM + 1;// child[0][i] = ノード i の左子// child[1][i] = ノード i の右子std::array<std::array<Node, MAX_NODE_NUM>, 2> child{};// weight[i] = ノード i とその親を結ぶ辺の重みstd::array<Weight, MAX_NODE_NUM> weight{};// 使用しているノードの個数size_t node_num = 0;Node create_node() {const Node new_node = node_num++;// 以前のテストケースの情報が残っている可能性があるので、初期化するchild[0][new_node] = child[1][new_node] = null_node;weight[new_node] = 0;return new_node;}void clear_nodes() {node_num = 0;}}// @returns floor(log_2(v))size_t bit_width(Value v) {size_t x = 0;while (Value(1) << (x + 1) <= v) ++x;return x;}// @returns true if the k-th bit of v is 1, false otherwisebool get_bit(Value v, size_t k) {return (v >> k) & 1;}int64_t solve(const size_t n, const size_t m,const std::vector<Value>& R,const std::vector<Value>& C,const std::vector<std::vector<Value>>& A) {static constexpr Weight INF = Weight(1) << 30;for (size_t i = 0; i < n; ++i) for (size_t j = 0; j < m; ++j) {if (A[0][0] ^ A[0][j] ^ A[i][0] ^ A[i][j]) {return -1;}}using binary_trie::Node;using binary_trie::clear_nodes, binary_trie::create_node;using binary_trie::null_node, binary_trie::child, binary_trie::weight, binary_trie::node_num;clear_nodes();const Node root = create_node();// f(x) += W * [(x ^ Y) > Z] for all xauto add_weight = [root](const Value Y, const Value Z, const Weight W) {const Value YZ = Y ^ Z;Node cur = root;for (size_t bit = BIT_NUM; bit-- > 0;) {const bool edge_label = get_bit(YZ, bit);if (child[edge_label][cur] == null_node) {child[edge_label][cur] = create_node();}Node nxt = child[edge_label][cur];// 対応する Z の bit が 0 のとき、cur の子のうち nxt でない方の子部分木にコスト W を加算if (not get_bit(Z, bit)) {weight[cur] += W;weight[nxt] -= W;}cur = nxt;}};auto add_weights = [add_weight](const Value Y, const Value v) {if (v > 0) {add_weight(Y, 0, 1);add_weight(Y, v + 1, 1);add_weight(Y, 2 * (1 << bit_width(v)) - 1, INF);} else {add_weight(Y, 0, INF);}};for (size_t i = 0; i < n; ++i) {const Value Y = A[0][0] ^ A[i][0];add_weights(Y, R[i]);}for (size_t j = 0; j < m; ++j) {const Value Y = A[0][j];add_weights(Y, C[j]);}Weight ans = INF;// 親節点ID < 子節点ID なので、IDを昇順に見れば正しく重みを伝播できるfor (Node node = 0; node < node_num; ++node) {for (const bool edge_label : { 0, 1 }) {const Node child_node = child[edge_label][node];if (child_node != null_node) {weight[child_node] += weight[node];} else {// 子節点が null ==> その子部分木の辺は全て重み0 ==> コスト確定ans = std::min(ans, weight[node]);}}}return ans != INF ? ans : -1;}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);size_t t;std::cin >> t;for (size_t case_id = 0; case_id < t; ++case_id) {size_t n, m;std::cin >> n >> m;std::vector<Value> R(n), C(m);for (auto&& elm : R) std::cin >> elm;for (auto&& elm : C) std::cin >> elm;std::vector A(n, std::vector<Value>(m));for (auto&& row : A) for (auto&& elm : row) std::cin >> elm;std::cout << solve(n, m, R, C, A) << '\n';}}