結果
問題 | No.5020 Averaging |
ユーザー | ぴぃいいいい |
提出日時 | 2024-02-27 07:13:22 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 971 ms / 1,000 ms |
コード長 | 7,789 bytes |
コンパイル時間 | 3,861 ms |
コンパイル使用メモリ | 194,876 KB |
実行使用メモリ | 62,548 KB |
スコア | 30,411,130 |
最終ジャッジ日時 | 2024-02-27 07:14:14 |
合計ジャッジ時間 | 51,283 ms |
ジャッジサーバーID (参考情報) |
judge14 / judge15 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 887 ms
61,752 KB |
testcase_01 | AC | 838 ms
61,752 KB |
testcase_02 | AC | 888 ms
61,752 KB |
testcase_03 | AC | 966 ms
61,752 KB |
testcase_04 | AC | 871 ms
61,752 KB |
testcase_05 | AC | 875 ms
61,752 KB |
testcase_06 | AC | 895 ms
61,752 KB |
testcase_07 | AC | 896 ms
61,752 KB |
testcase_08 | AC | 880 ms
61,752 KB |
testcase_09 | AC | 866 ms
61,752 KB |
testcase_10 | AC | 879 ms
61,752 KB |
testcase_11 | AC | 893 ms
61,752 KB |
testcase_12 | AC | 833 ms
62,436 KB |
testcase_13 | AC | 885 ms
61,752 KB |
testcase_14 | AC | 877 ms
61,752 KB |
testcase_15 | AC | 886 ms
61,752 KB |
testcase_16 | AC | 833 ms
61,752 KB |
testcase_17 | AC | 861 ms
61,752 KB |
testcase_18 | AC | 884 ms
61,752 KB |
testcase_19 | AC | 856 ms
61,752 KB |
testcase_20 | AC | 856 ms
61,752 KB |
testcase_21 | AC | 874 ms
61,752 KB |
testcase_22 | AC | 882 ms
61,752 KB |
testcase_23 | AC | 862 ms
61,752 KB |
testcase_24 | AC | 879 ms
61,752 KB |
testcase_25 | AC | 854 ms
61,752 KB |
testcase_26 | AC | 894 ms
61,752 KB |
testcase_27 | AC | 867 ms
61,752 KB |
testcase_28 | AC | 893 ms
61,752 KB |
testcase_29 | AC | 852 ms
61,752 KB |
testcase_30 | AC | 901 ms
61,752 KB |
testcase_31 | AC | 863 ms
61,752 KB |
testcase_32 | AC | 850 ms
61,752 KB |
testcase_33 | AC | 886 ms
61,752 KB |
testcase_34 | AC | 963 ms
62,424 KB |
testcase_35 | AC | 882 ms
61,752 KB |
testcase_36 | AC | 835 ms
61,752 KB |
testcase_37 | AC | 868 ms
61,752 KB |
testcase_38 | AC | 852 ms
61,752 KB |
testcase_39 | AC | 889 ms
61,752 KB |
testcase_40 | AC | 851 ms
61,752 KB |
testcase_41 | AC | 851 ms
61,752 KB |
testcase_42 | AC | 869 ms
61,752 KB |
testcase_43 | AC | 860 ms
61,752 KB |
testcase_44 | AC | 861 ms
61,752 KB |
testcase_45 | AC | 858 ms
62,548 KB |
testcase_46 | AC | 892 ms
61,752 KB |
testcase_47 | AC | 971 ms
61,752 KB |
testcase_48 | AC | 877 ms
61,752 KB |
testcase_49 | AC | 848 ms
61,752 KB |
ソースコード
#pragma GCC target("avx") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #include <utility> #include <algorithm> #include <iostream> #include <memory> #include <vector> #include <optional> #include <unordered_set> #include <cassert> #include <chrono> using namespace std; using ull = unsigned long long; using ll = long long; using vll = vector<ll>; inline double get_time() { using namespace std::chrono; return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); } double start_time = get_time(); struct IO{ int n; vll a,b; IO(){} void input(){ cin >> n; a.resize(n); b.resize(n); for(int i=0;i<n;i++){ cin >> a[i] >> b[i]; } } }; //操作を表す構造体 struct Operation{ size_t x,y; }; //操作を元に戻すための情報を表す構造体 struct RollbackOperation{ size_t x,y; pair<ll,ll> x_val; pair<ll,ll> y_val; }; struct State{ IO *io; vll a,b; //初期状態の生成 State(IO &_io) : io(&_io){ a = io->a; b = io->b; }; //スコア計算 ull score(){ ll diff_a = a[0] - 500000000000000000ll; ll diff_b = b[0] - 500000000000000000ll; return max(abs(diff_a),abs(diff_b)); }; //ハッシュ値計算 ull hash(){ ull h = 0; for(int i=0;i<io->n;i++){ h ^= a[i]; h ^= b[i]; } return h; }; //状態を更新せずスコアとハッシュのみを計算 pair<ull,ull> try_apply(Operation op, ull score, ull hash){ if(op.x==0 || op.y==0){ ll a_ave = (a[op.x] + a[op.y])/2; ll b_ave = (b[op.x] + b[op.y])/2; ll a_diff = abs(a_ave-500000000000000000ll); ll b_diff = abs(b_ave-500000000000000000ll); score = max(a_diff,b_diff); } hash ^= a[op.x]; hash ^= b[op.x]; hash ^= a[op.y]; hash ^= b[op.y]; return {score,hash}; }; //状態を更新する //元の状態に戻すための情報を返す RollbackOperation apply(Operation op){ ll a_ave = (a[op.x] + a[op.y])/2; ll b_ave = (b[op.x] + b[op.y])/2; RollbackOperation rop = {op.x,op.y,{a[op.x],b[op.x]},{a[op.y],b[op.y]}}; a[op.x] = a_ave; b[op.x] = b_ave; a[op.y] = a_ave; b[op.y] = b_ave; return rop; } //applyから返された情報を元に状態を戻す void rollback(RollbackOperation op){ a[op.x] = op.x_val.first; b[op.x] = op.x_val.second; a[op.y] = op.y_val.first; b[op.y] = op.y_val.second; } }; struct Node; struct Cand{ Operation op; shared_ptr<Node> parent; ull score; ull hash; ull p; //優先度 }; using Parent = optional<pair<Operation,shared_ptr<Node>>>; using Children = vector<pair<Operation,weak_ptr<Node>>>; struct Node{ Parent parent; Children child; ull score; ull hash; Node(Parent parent, Children child, ull score, ull hash): parent(parent),child(child),score(score),hash(hash){} }; // 多スタート用に構造体にまとめておくと楽 struct Tree{ State state; shared_ptr<Node> node; ull rank; // 注意: depthは深くなっていくごとに-1されていく void dfs(vector<Cand>& next_states,bool one,ull& p,ull depth){ if(depth==0){ ull score=node->score; ull hash=node->hash; // 検算 // assert(score==state.score()); // assert(hash==state.hash()); vector<Operation> ops; //次の操作を列挙 for(int i=0;i<state.io->n;i++){ for(int j=i+1;j<state.io->n;j++){ if(i==j) continue; ops.emplace_back(i,j); } } //次の操作を全部試す for(auto const& op:ops){ auto [next_score,next_hash]=state.try_apply(op,score,hash); next_states.emplace_back(Cand{op,node,next_score,next_hash,p}); p+=1; } } else{ auto node_backup=node; auto child=&node_backup->child; // 有効な子だけにする child->erase(remove_if(child->begin(),child->end(),[](pair<Operation,weak_ptr<Node>>& x){return x.second.expired();}),child->end()); bool next_one=one&child->size()==1; // 定数調整の必要あり if(depth==5){ p=0; } ++rank; for(const auto& [op,ptr]:*child){ node=ptr.lock(); RollbackOperation backup=state.apply(op); dfs(next_states,next_one,p,depth-1); if(!next_one){ state.rollback(backup); } } if(!next_one){ node=node_backup; --rank; } } } }; vector<Operation> beam(IO &io){ constexpr ull turn = 50; constexpr ull beam_width = 1000; State state(io); ull score = state.score(); ull hash = state.hash(); // 検算 /* assert(score==state.score()); assert(hash==state.hash()); */ Tree tree{move(state), shared_ptr<Node>(new Node(Parent(),Children(),score,hash)),0}; vector<shared_ptr<Node>> cur{tree.node}; vector<Cand> next_states; unordered_set<ull> hash_set; for(ull i=0;i<turn;i++){ next_states.clear(); ull tmp = 0; tree.dfs(next_states,true,tmp,i-tree.rank); #ifndef ONLINE_JUDGE cerr << "turn : " << i << " size : " << next_states.size() << endl; #endif if(i+1!=turn){ //上位beam_width個だけ残す if(next_states.size() > beam_width){ nth_element(next_states.begin(),next_states.begin()+beam_width,next_states.end(), [](Cand& a, Cand& b){ if(a.score == b.score){ return a.p > b.p; } else return a.score < b.score; }); next_states.erase(next_states.begin()+beam_width,next_states.end()); } cur.clear(); hash_set.clear(); for(const auto&[op,parent,next_score,next_hash,p]:next_states){ //重複除去 if(hash_set.count(next_hash)==0){ hash_set.insert(next_hash); auto child_ptr=shared_ptr<Node>(new Node(Parent({op,parent}),Children(),score,hash)); parent->child.emplace_back(op,weak_ptr<Node>(child_ptr)); cur.emplace_back(child_ptr); } } } } //最良の状態を選択 ull arg_min = -1; ull min = 1ull<<60; for(ull i=0;i<next_states.size();i++){ if(next_states[i].score<=min){ min=next_states[i].score; arg_min=i; } } auto [op,ptr,best_score,_,__]=next_states[arg_min]; #ifndef ONLINE_JUDGE cerr << "best score : " << best_score << endl; cerr<<"rank: "<<turn-tree.rank<<endl; #endif vector<Operation> ret{op}; // 操作の復元 while(ptr->parent.has_value()){ auto [op,parent]=ptr->parent.value(); ret.emplace_back(op); ptr=parent; } reverse(ret.begin(),ret.end()); return ret; } int main(){ IO io; io.input(); auto ops = beam(io); cout << ops.size() << endl; for(auto [x,y]:ops){ cout << x+1 << " " << y+1 << endl; } #ifndef ONLINE_JUDGE cerr << "time : " << get_time()-start_time << "ms" << endl; #endif }