結果
問題 | No.5020 Averaging |
ユーザー | wanui |
提出日時 | 2024-03-03 01:53:36 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 907 ms / 1,000 ms |
コード長 | 12,886 bytes |
コンパイル時間 | 3,452 ms |
コンパイル使用メモリ | 247,564 KB |
実行使用メモリ | 69,764 KB |
スコア | 83,817,834 |
最終ジャッジ日時 | 2024-03-03 01:54:30 |
合計ジャッジ時間 | 50,554 ms |
ジャッジサーバーID (参考情報) |
judge15 / judge11 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 885 ms
69,764 KB |
testcase_01 | AC | 902 ms
69,764 KB |
testcase_02 | AC | 901 ms
69,764 KB |
testcase_03 | AC | 871 ms
69,764 KB |
testcase_04 | AC | 872 ms
69,764 KB |
testcase_05 | AC | 886 ms
69,764 KB |
testcase_06 | AC | 865 ms
69,764 KB |
testcase_07 | AC | 894 ms
69,764 KB |
testcase_08 | AC | 866 ms
69,764 KB |
testcase_09 | AC | 899 ms
69,764 KB |
testcase_10 | AC | 849 ms
69,764 KB |
testcase_11 | AC | 850 ms
69,764 KB |
testcase_12 | AC | 907 ms
69,764 KB |
testcase_13 | AC | 824 ms
69,764 KB |
testcase_14 | AC | 875 ms
69,764 KB |
testcase_15 | AC | 872 ms
69,764 KB |
testcase_16 | AC | 840 ms
69,764 KB |
testcase_17 | AC | 828 ms
69,764 KB |
testcase_18 | AC | 900 ms
69,764 KB |
testcase_19 | AC | 893 ms
69,764 KB |
testcase_20 | AC | 861 ms
69,764 KB |
testcase_21 | AC | 895 ms
69,764 KB |
testcase_22 | AC | 874 ms
69,764 KB |
testcase_23 | AC | 864 ms
69,764 KB |
testcase_24 | AC | 845 ms
69,764 KB |
testcase_25 | AC | 890 ms
69,764 KB |
testcase_26 | AC | 894 ms
69,764 KB |
testcase_27 | AC | 863 ms
69,764 KB |
testcase_28 | AC | 890 ms
69,764 KB |
testcase_29 | AC | 866 ms
69,764 KB |
testcase_30 | AC | 900 ms
69,764 KB |
testcase_31 | AC | 854 ms
69,764 KB |
testcase_32 | AC | 872 ms
69,764 KB |
testcase_33 | AC | 891 ms
69,764 KB |
testcase_34 | AC | 840 ms
69,764 KB |
testcase_35 | AC | 848 ms
69,764 KB |
testcase_36 | AC | 873 ms
69,764 KB |
testcase_37 | AC | 878 ms
69,764 KB |
testcase_38 | AC | 834 ms
69,764 KB |
testcase_39 | AC | 877 ms
69,764 KB |
testcase_40 | AC | 874 ms
69,764 KB |
testcase_41 | AC | 842 ms
69,764 KB |
testcase_42 | AC | 860 ms
69,764 KB |
testcase_43 | AC | 869 ms
69,764 KB |
testcase_44 | AC | 892 ms
69,764 KB |
testcase_45 | AC | 873 ms
69,764 KB |
testcase_46 | AC | 835 ms
69,764 KB |
testcase_47 | AC | 869 ms
69,764 KB |
testcase_48 | AC | 861 ms
69,764 KB |
testcase_49 | AC | 840 ms
69,764 KB |
ソースコード
#include <bits/stdc++.h> // clang-format off using namespace std; using ll=long long; #define debug1(a) { cerr<<#a<<":"<<a<<endl; } #define debug2(a,b) { cerr<<#a<<":"<<a<<" "<<#b<<":"<<b<<endl; } #define debug3(a,b,c) { cerr<<#a<<":"<<a<<" "<<#b<<":"<<b<<" "<<#c<<":"<<c<<endl; } #define debug4(a,b,c,d) { cerr<<#a<<":"<<a<<" "<<#b<<":"<<b<<" "<<#c<<":"<<c<<" "<<#d<<":"<<d<<endl; } struct card_t { ll a; ll b; }; bool operator==(const card_t &lhs, const card_t &rhs) { return (lhs.a == rhs.a && lhs.b == rhs.b); } bool operator!=(const card_t &lhs, const card_t &rhs) { return !(lhs == rhs); } bool operator<(const card_t &lhs, const card_t &rhs) { if (lhs.a != rhs.a){return lhs.a<rhs.a;} return lhs.b<rhs.b; } card_t avgfunc(card_t x, card_t y){ return card_t{(x.a+y.a)/2,(x.b+y.b)/2}; } std::ostream &operator<<(std::ostream &os, card_t &pt) { string s; s = "(" + to_string(ll(pt.a)) + ", " + to_string(ll(pt.b)) + ")"; return os << s; }; // clang-format on namespace marathon { mt19937 engine(0); clock_t start_time; double now() { return 1000.0 * (clock() - start_time) / CLOCKS_PER_SEC; } void marathon_init() { start_time = clock(); random_device seed_gen; engine.seed(seed_gen()); } int randint(int mn, int mx) { int rng = mx - mn + 1; return mn + (engine() % rng); } double uniform(double x, double y) { const int RND = 1e8; double mean = (x + y) / 2.0; double dif = y - mean; double p = double(engine() % RND) / RND; return mean + dif * (1.0 - 2.0 * p); } bool anneal_accept(double new_score, double old_score, double cur_time, double begin_time, double end_time, double begin_temp, double end_temp) { const int ANNEAL_RND = 1e8; const double ANNEAL_EPS = 1e-6; double temp = (begin_temp * (end_time - cur_time) + end_temp * (cur_time - begin_time)) / (end_time - begin_time); return (exp((new_score - old_score) / temp) > double(engine() % ANNEAL_RND) / ANNEAL_RND + ANNEAL_EPS); } } // namespace marathon const int OPLIMIT = 50; const int N = 45; const ll F17 = 500000000000000000ll; card_t INIT_AB[N]; double evaluate(card_t x) { double da = abs(x.a - F17); double db = abs(x.b - F17); return max(da, db) * 100 + min(da, db); } double evaluate2(card_t x, card_t dest) { double da = abs(x.a - dest.a); double db = abs(x.b - dest.b); return max(da, db) * 100 + min(da, db); } void rec(vector<int> &ops, vector<bool> &used, pair<double, vector<int>> &best_result, card_t used_total, card_t target, int lastind, int maxops, vector<card_t> &now_cards) { if (ops.size() >= 1) { auto new_zero = avgfunc(used_total, now_cards[lastind]); double e = evaluate(new_zero); if (e < best_result.first) { best_result = {e, ops}; } } if (ops.size() >= maxops) { return; } for (int j = 0; j < N; j++) { if (used[j]) continue; used[j] = true; ops.push_back(j); card_t nxt_used_total = (used_total.a <= 0) ? now_cards[j] : avgfunc(now_cards[j], used_total); rec(ops, used, best_result, nxt_used_total, target, lastind, maxops, now_cards); ops.pop_back(); used[j] = false; } } void do_op(int i, int j, vector<card_t> &now_cards, vector<pair<int, int>> &result) { card_t avg_ = avgfunc(now_cards[i], now_cards[j]); now_cards[i] = avg_; now_cards[j] = avg_; result.push_back({i, j}); } void output(vector<pair<int, int>> &result) { cout << result.size() << endl; for (auto p : result) { cout << p.first + 1 << " " << p.second + 1 << endl; } } namespace BeamSearch { using FORWARD_OP = pair<int, int>; using BACKWARD_OP = tuple<int, ll, ll>; struct node_t { int id; int parent_id; int first_child_id; int next_sibling_id; int depth; bool leaf; FORWARD_OP fwd; BACKWARD_OP bwd; double score; double realscore; }; bool operator<(const node_t &lhs, const node_t &rhs) { return lhs.score < rhs.score; } node_t node_store[500000]; int _node_store_size = 0; int use_node_id() { _node_store_size++; return _node_store_size - 1; } void add_node_store(node_t &node) { node_store[node.id] = node; } struct board_t { bitset<N> used; vector<card_t> cards; ll a; ll b; }; class BeamSearch { public: board_t boardsrc; BeamSearch(board_t &board) { boardsrc = board; } void add_new_leafs(vector<node_t> &new_leafs, int beamwidth) { // 見つけた頂点のうちスコアが高いものを木に追加 if (new_leafs.size() > beamwidth) { sort(new_leafs.rbegin(), new_leafs.rend()); new_leafs.resize(beamwidth); } unordered_map<int, int> lastchild_map; for (auto leaf_ : new_leafs) { leaf_.id = use_node_id(); add_node_store(leaf_); auto &leaf = node_store[leaf_.id]; leaf.next_sibling_id = -1; auto &parent = node_store[leaf_.parent_id]; if (parent.first_child_id < 0) { parent.first_child_id = leaf.id; lastchild_map[parent.id] = leaf.id; } else { int lc = lastchild_map[parent.id]; node_store[lc].next_sibling_id = leaf.id; lastchild_map[parent.id] = leaf.id; } } } void to_child(node_t &parent, node_t &child, board_t &board) { // 親から子に移動するときのboardの変化を適用 int depth = child.fwd.first; int cardid = child.fwd.second; board.used[cardid] = true; board.a += board.cards[cardid].a / (2ll << depth); board.b += board.cards[cardid].b / (2ll << depth); } void to_parent(node_t &child, node_t &parent, board_t &board) { // 子から親に移動するときのboardの変化を適用 int cardid; ll pa, pb; tie(cardid, pa, pb) = child.bwd; board.used[cardid] = false; board.a = pa; board.b = pb; } double evaluate_score(node_t &node, board_t &board) { // スコア計算 int depth = node.fwd.first; // int cardid = node.fwd.second; ll a = board.a + F17 / (2ll << depth); ll b = board.b + F17 / (2ll << depth); return -evaluate({a, b}); } double evaluate_realscore(node_t &node, board_t &board) { // 実スコア計算 (不要な場合もある) int depth = node.fwd.first; int cardid = node.fwd.second; ll a = board.a + board.cards[cardid].a / (2ll << depth); ll b = board.b + board.cards[cardid].b / (2ll << depth); return -evaluate({a, b}); } void set_forward_backward_ops(node_t &child, node_t &parent, board_t &board, int cardid) { // 親から子、子から親に移動するときの操作をセット child.fwd = {child.depth, cardid}; child.bwd = {cardid, board.a, board.b}; } node_t make_child(node_t &parent, board_t &board, int op) { node_t child; { child.id = 1e9; child.parent_id = parent.id; child.first_child_id = -1; child.next_sibling_id = -1; child.depth = parent.depth + 1; child.leaf = true; } set_forward_backward_ops(child, parent, board, op); to_child(parent, child, board); child.score = evaluate_score(child, board); child.realscore = evaluate_realscore(child, board); to_parent(child, parent, board); return child; } void generate_new_leafs(int parent_id, board_t &board, vector<node_t> &new_leafs) { // 子を生成し、 評価して新しい葉の候補として追加 auto &parent = node_store[parent_id]; for (int op = 0; op < N; op++) { if (board.used[op]) continue; if (board.a >= F17 + 10000) continue; if (board.b >= F17 + 10000) continue; node_t child = make_child(parent, board, op); new_leafs.push_back(child); } } void bs_rec(int node_id, board_t &board, vector<node_t> &new_leafs) { node_t &curnode = node_store[node_id]; int before_new_leafs_cnt = new_leafs.size(); if (curnode.leaf) { // 子を生成して新しい葉の候補として追加。この頂点はもう葉でなくなる generate_new_leafs(node_id, board, new_leafs); node_store[node_id].leaf = false; } else { // 子を順にたどる if (curnode.first_child_id >= 0) { auto child = node_store[curnode.first_child_id]; while (true) { to_child(curnode, child, board); bs_rec(child.id, board, new_leafs); to_parent(child, curnode, board); if (child.next_sibling_id < 0) break; child = node_store[child.next_sibling_id]; } } } int after_new_leafs_cnt = new_leafs.size(); if (before_new_leafs_cnt == after_new_leafs_cnt) { node_store[node_id].first_child_id = -1; // 新しい葉候補を発見できていなければこの頂点はもう探索しなくていい } } vector<int> beamsearch(int opnum) { node_t init_state = node_t(); { init_state.id = use_node_id(); init_state.parent_id = -1; init_state.next_sibling_id = -1; init_state.first_child_id = -1; init_state.fwd = {-1, -1}; init_state.bwd = {-1, -1, -1}; init_state.depth = 0; init_state.leaf = true; init_state.score = -1e18; init_state.realscore = -1e18; add_node_store(init_state); } int beamwidth = 4000; for (int op = 1; op <= opnum; op++) { debug2(op, _node_store_size); vector<node_t> new_leafs; bs_rec(0, boardsrc, new_leafs); add_new_leafs(new_leafs, beamwidth); } { node_t bestnode; bestnode.realscore = -1e18; for (int nodeid = 0; nodeid < _node_store_size; nodeid++) { auto node = node_store[nodeid]; if (node.depth != opnum - 1) continue; // TODO if (node.realscore > bestnode.realscore) bestnode = node; } vector<int> ops; auto node = bestnode; while (node.id > 0) { ops.push_back(node.fwd.second); node = node_store[node.parent_id]; } reverse(ops.begin(), ops.end()); return ops; } } }; } // namespace BeamSearch void solve() { vector<card_t> now_cards(N); for (int i = 0; i < N; i++) { now_cards[i] = INIT_AB[i]; } vector<pair<int, int>> result; { tuple<double, int, int, int> bestresult = {-1e50, -1, -1, -1}; for (int x = 1; x < N; x++) { for (int y = 1; y < N; y++) { if (x == y) continue; for (int z = 1; z < N; z++) { if (x == z) continue; if (y == z) continue; card_t c0 = now_cards[0]; card_t cx = now_cards[x]; card_t cy = now_cards[y]; card_t cz = now_cards[z]; card_t nxt_c0 = {c0.a / 2 + cx.a / 4 + cy.a / 8 + cz.a / 8, c0.b / 2 + cx.b / 4 + cy.b / 8 + cz.b / 8}; double score = -evaluate(nxt_c0); bestresult = max(bestresult, {score, x, y, z}); } } } { double score; int x, y, z; tie(score, x, y, z) = bestresult; do_op(z, y, now_cards, result); do_op(y, x, now_cards, result); do_op(x, 0, now_cards, result); } } debug2(evaluate(now_cards[0]), now_cards[0]); { BeamSearch::board_t board; board.a = now_cards[0].a / 2; board.b = now_cards[0].b / 2; board.used = 0; board.used[0] = 1; board.cards = now_cards; auto ops = BeamSearch::BeamSearch(board).beamsearch(44); int m = ops.size(); if (m > 0) { for (int i = m - 1; i >= 1; i--) { do_op(ops[i], ops[i - 1], now_cards, result); } do_op(0, ops[0], now_cards, result); } } debug2(evaluate(now_cards[0]), now_cards[0]); debug1(marathon::now()); output(result); } int main() { marathon::marathon_init(); int n; cin >> n; for (int i = 0; i < n; i++) { ll a, b; cin >> a >> b; INIT_AB[i] = card_t{a, b}; } solve(); return 0; }