結果
問題 | No.5020 Averaging |
ユーザー |
|
提出日時 | 2024-02-25 15:06:19 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 953 ms / 1,000 ms |
コード長 | 10,400 bytes |
コンパイル時間 | 8,259 ms |
コンパイル使用メモリ | 351,208 KB |
実行使用メモリ | 6,676 KB |
スコア | 50,388,579 |
最終ジャッジ日時 | 2024-02-25 15:07:18 |
合計ジャッジ時間 | 58,129 ms |
ジャッジサーバーID (参考情報) |
judge11 / judge14 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
#pragma GCC optimize("O3")#pragma GCC optimize("unroll-loops")#ifdef ONLINE_JUDGE// #define NDEBUG#endif // ONLINE_JUDGE#include <bits/stdc++.h>#include <atcoder/all>#ifndef ONLINE_JUDGE#include <omp.h>#endif // ONLINE_JUDGEusing namespace std;using namespace atcoder;#define ll long long int#define ull unsigned long long inttemplate<class T>inline bool chmin(T& a, T b) {if (a > b) {a = b;return true;}return false;}class Xorshift {public:explicit Xorshift(uint32_t seed): x_(seed) {assert(seed);}// [0, stop)uint32_t randrange(uint32_t stop) {assert(stop > 0);next();return x_ % stop;}// [start, stop)uint32_t randrange(uint32_t start, uint32_t stop) {assert(start < stop);next();return start + x_ % (stop - start);}// [a, b]uint32_t randint(uint32_t a, uint32_t b) {assert(a <= b);return randrange(a, b + 1);}// [0.0, 1.0]double random() {next();return static_cast<double>(x_) * (1.0 / static_cast<double>(UINT32_MAX));}// [a, b] or [b, a]double uniform(double a, double b) {return a + (b - a) * random();}private:uint32_t x_;void next() {x_ ^= x_ << 13;x_ ^= x_ >> 17;x_ ^= x_ << 5;}};class IndexSet {public:explicit IndexSet(int n): n_(n), positions_(n, -1) {}void insert(int x) {assert(0 <= x && x < n_);assert(!contains(x));positions_[x] = data_.size();data_.push_back(x);}void erase(int x) {assert(0 <= x && x < n_);assert(contains(x));int i = positions_[x];int y = data_.back();data_[i] = y;data_.pop_back();positions_[y] = i;positions_[x] = -1;}bool contains(int x) const {assert(0 <= x && x < n_);return positions_[x] != -1;}int choice(Xorshift& rng) const {assert(!data_.empty());return data_[rng.randrange(data_.size())];}const vector<int>& get_data() const {return data_;}size_t size() const {return data_.size();}void clear() {for (int x : data_) {positions_[x] = -1;}data_.clear();}private:int n_;vector<int> data_;vector<int> positions_;};class Timer {public:explicit Timer() {begin();elapsed_time_ = 0.0;}void begin() {start_time_ = chrono::system_clock::now();}double get_time() {chrono::system_clock::time_point end_time = chrono::system_clock::now();elapsed_time_ = chrono::duration_cast<chrono::nanoseconds>(end_time - start_time_).count();elapsed_time_ *= 1e-9; // from nanoseconds to secondsreturn elapsed_time_;}double get_last_time() const {return elapsed_time_;}bool yet(double time_limit) {return get_time() < time_limit;}private:chrono::system_clock::time_point start_time_;double elapsed_time_;};constexpr int sa_time_counts = 1 << 4;constexpr size_t sa_random_steps = 1ul << 12;class SimulatedAnnealing {public:explicit SimulatedAnnealing(double t_first, double t_last, bool exponential, double time_limit, uint_fast32_t seed): t_first_(t_first), t_last_(t_last), exponential_(exponential), time_limit_(time_limit) {assert(0.0 <= t_last_ && t_last_ <= t_first_);time_counter_ = sa_time_counts;temperature_ = t_first_;log2_random_index_ = 0;for (size_t i = 0; i < sa_random_steps; ++i) {log2_random_[i] = log2(static_cast<double>(i + 1) / static_cast<double>(sa_random_steps));}mt19937 rng(seed);shuffle(log2_random_.begin(), log2_random_.end(), rng);}template<class T>bool accept(T profit, const Timer& timer) {if (profit >= static_cast<T>(0)) {return true;} else {return static_cast<double>(profit) > get_threshold(timer);}}double get_threshold(const Timer& timer) {update_temperature(timer);++log2_random_index_;log2_random_index_ &= (sa_random_steps - 1ul);return temperature_ * log2_random_[log2_random_index_];}private:double t_first_, t_last_;bool exponential_;double time_limit_;int time_counter_;double temperature_;size_t log2_random_index_;array<double,sa_random_steps> log2_random_;void update_temperature(const Timer& timer) {if (time_counter_-- == 0) {time_counter_ = sa_time_counts;double progress = timer.get_last_time() / time_limit_;if (exponential_) {temperature_ = pow(t_first_, 1.0 - progress) * pow(t_last_, progress);} else {temperature_ = t_first_ * (1.0 - progress) + t_last_ * progress;}}}};constexpr double time_limit = 0.95;constexpr int n = 45;constexpr int max_turn = 50;constexpr ll goal = 5e17;constexpr ll sum_goal = 1e18;struct Input {array<pair<ll,ll>,n> cards;void input() {int _n;cin >> _n;assert(_n == n);for (int i = 0; i < n; ++i) {cin >> cards[i].first >> cards[i].second;}}void input(const string& filename) {ifstream in(filename);assert(in);int _n;in >> _n;assert(_n == n);for (int i = 0; i < n; ++i) {in >> cards[i].first >> cards[i].second;}}};constexpr double t0 = 0.5;constexpr double t1 = 0.1;struct Solver {Timer timer;Xorshift rng;const Input input;vector<pair<int,int>> best_ans;ll min_cost;Solver(const Input& input): rng(1), input(input) {}vector<pair<int,int>> init_ans() {vector<pair<int,int>> ans(max_turn);for (int turn = 0; turn < max_turn; ++turn) {do {ans[turn].first = choose_first(turn) ? 0 : rng.randrange(1, n);ans[turn].second = rng.randrange(1, n);} while (ans[turn].first == ans[turn].second);}return ans;}bool choose_first(int turn) {return (int)rng.randrange(max_turn) < turn;}ll calc_cost(const vector<pair<int,int>>& ans) {array<pair<ll,ll>,n> cards = input.cards;for (auto [u, v] : ans) {ll a = (cards[u].first + cards[v].first) / 2;ll b = (cards[u].second + cards[v].second) / 2;cards[u] = {a, b};cards[v] = {a, b};}return max(abs(cards[0].first - goal), abs(cards[0].second - goal));}void solve() {SimulatedAnnealing sa(t0, t1, false, time_limit, 0);vector<pair<int,int>> ans = init_ans();ll cost = calc_cost(ans);best_ans = ans;min_cost = cost;while (timer.yet(time_limit)) {int turn = rng.randrange(ans.size());auto [a, b] = ans[turn];int u = choose_first(turn) ? 0 : rng.randrange(1, n);int v = rng.randrange(n - 1);if (v >= u) {++v;}ans[turn] = {u, v};ll new_cost = calc_cost(ans);if (new_cost < cost || sa.accept(log2(cost) - log2(new_cost), timer)) {cost = new_cost;if (chmin(min_cost, cost)) {best_ans = ans;}} else {ans[turn] = {a, b};}}}void print() const {cout << best_ans.size() << "\n";for (auto [u, v] : best_ans) {cout << u + 1 << " " << v + 1 << "\n";}}void print(const string& filename) const {ofstream out(filename);assert(out);out << best_ans.size() << "\n";for (auto [u, v] : best_ans) {out << u + 1 << " " << v + 1 << "\n";}}ll score() const {return 2000000 - 100000 * log10(min_cost + 1);}};void multi_test(int cases, int num_threads) {if (cases <= 0) {return;}cerr << "cases: " << cases << endl;vector<ll> scores(cases);vector<double> times(cases);#ifndef ONLINE_JUDGEomp_set_num_threads(num_threads);#pragma omp parallel for#endif // ONLINE_JUDGEfor (int seed = 0; seed < cases; ++seed) {string filename = to_string(seed + 1);filename = "in/in" + string(3 - filename.size(), '0') + filename + ".txt";Input input;input.input(filename);Solver solver(input);solver.solve();times[seed] = solver.timer.get_time();scores[seed] = solver.score();cerr << filename << " " << scores[seed] << " " << times[seed] << " sec" << endl;solver.print("out" + filename.substr(2));}cerr << "Average Score: " << accumulate(scores.begin(), scores.end(), 0ll) / cases << endl;cerr << "Max Time: " << *max_element(times.begin(), times.end()) << " sec" << endl;cerr << "Average Time: " << accumulate(times.begin(), times.end(), 0.0) / cases << " sec" << endl;}int main() {ios::sync_with_stdio(false);std::cin.tie(nullptr);Input input;input.input();Solver solver(input);solver.solve();solver.print();#ifndef ONLINE_JUDGEcerr << "Score = " << solver.score() << ", " << solver.timer.get_time() << " sec" << endl;int cases = 50;int num_threads = 10;multi_test(cases, num_threads);#endif // ONLINE_JUDGEreturn 0;}