結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー Keroru
提出日時 2026-02-27 21:52:47
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 957 ms / 1,000 ms
コード長 13,938 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,873 ms
コンパイル使用メモリ 387,488 KB
実行使用メモリ 7,976 KB
スコア 31,920,339
最終ジャッジ日時 2026-02-27 21:54:38
合計ジャッジ時間 107,411 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

// baseline_score_0000_0014: 4062458
// improved_score_0000_0014: 4579779
// score_improvement_0000_0014: +517321
// 方針: 人口上位都市を中心に初期解を作り、連続化評価(exp平滑)と逆順DPで高速評価しながら焼きなましで時刻表を改善する。
// 変更点: 敵(スクエア航空)の強い航路を使う初期解、ドミノ倒し修復つき近傍(時刻シフト/目的地変更/挿入/削除)、終盤の全都市厳密化を実装。

#include <bits/stdc++.h>
using namespace std;

constexpr int START_TIME = 6 * 60;
constexpr int END_TIME = 21 * 60;
constexpr double TL_SEC = 0.95;
constexpr double SA_TEMP_START = 200000.0;
constexpr double SA_TEMP_END = 2000.0;
constexpr double SMOOTH_C_START = 40.0;
constexpr double SMOOTH_C_END = 5.0;

struct Flight {
    int a, s, b, t;
};

struct Input {
    int N, R;
    vector<int> x, y, w;
    int M;
    vector<Flight> square;
    int K;
};

struct EvalResult {
    double smooth_score;
    long long binary_score;
};

struct XorShift {
    uint64_t x = 88172645463325252ULL;
    uint64_t next() {
        x ^= x << 7;
        x ^= x >> 9;
        return x;
    }
    int next_int(int l, int r) { return l + int(next() % uint64_t(r - l + 1)); }
    double next_double() { return (next() >> 11) * (1.0 / (1ULL << 53)); }
};

static int parse_time(const string& ts) {
    return (ts[0] - '0') * 600 + (ts[1] - '0') * 60 + (ts[3] - '0') * 10 + (ts[4] - '0');
}

static string fmt_time(int t) {
    ostringstream oss;
    oss << setw(2) << setfill('0') << (t / 60) << ':' << setw(2) << setfill('0') << (t % 60);
    return oss.str();
}

static int ceil5(int t) {
    if (t % 5 == 0) return t;
    return t + (5 - t % 5);
}

struct Solver {
    const Input& in;
    vector<vector<int>> dur;
    vector<pair<int, int>> pop_order;
    vector<int> top_cities;
    vector<pair<int, int>> enemy_strong_pairs;
    vector<int> target_times;
    vector<vector<vector<int>>> sq_latest;
    vector<vector<char>> valid_pair;
    XorShift rng;

    explicit Solver(const Input& in_) : in(in_) {
        build_duration();
        build_priority();
        build_enemy_strong_pairs();
        build_targets();
        precompute_square_latest();
        build_valid_pair();
    }

    void build_duration() {
        dur.assign(in.N, vector<int>(in.N, 0));
        for (int i = 0; i < in.N; ++i) for (int j = 0; j < in.N; ++j) if (i != j) {
            double d = hypot(double(in.x[i] - in.x[j]), double(in.y[i] - in.y[j]));
            double raw = 60.0 * d / 800.0 + 40.0;
            dur[i][j] = int(ceil(raw / 5.0) * 5.0);
        }
    }

    void build_priority() {
        pop_order.clear();
        for (int i = 0; i < in.N; ++i) pop_order.push_back({in.w[i], i});
        sort(pop_order.rbegin(), pop_order.rend());
        int use = min(in.N, 15);
        top_cities.clear();
        for (int i = 0; i < use; ++i) top_cities.push_back(pop_order[i].second);
    }

    void build_targets() {
        target_times.clear();
        for (int t = 11 * 60; t <= 21 * 60; t += 30) target_times.push_back(t);
    }

    void build_enemy_strong_pairs() {
        vector<vector<double>> score(in.N, vector<double>(in.N, 0.0));
        for (const auto& f : in.square) {
            score[f.a][f.b] += double(in.w[f.a]) * in.w[f.b];
        }

        struct Cand {
            double score;
            int u, v;
        };
        vector<Cand> cands;
        cands.reserve(in.N * (in.N - 1) / 2);
        for (int i = 0; i < in.N; ++i) {
            for (int j = i + 1; j < in.N; ++j) {
                double s = score[i][j] + score[j][i];
                if (s <= 0.0) continue;
                cands.push_back({s, i, j});
            }
        }
        sort(cands.begin(), cands.end(), [](const Cand& l, const Cand& r) { return l.score > r.score; });

        enemy_strong_pairs.clear();
        for (const auto& c : cands) enemy_strong_pairs.push_back({c.u, c.v});
    }

    vector<int> latest_departures(const vector<Flight>& sorted_desc, int target_city, int target_time) const {
        const int NEG = -1e9;
        vector<int> latest(in.N, NEG);
        latest[target_city] = target_time;
        for (const auto& f : sorted_desc) {
            if (f.t <= latest[f.b]) latest[f.a] = max(latest[f.a], f.s);
        }
        return latest;
    }

    void precompute_square_latest() {
        vector<Flight> sq = in.square;
        sort(sq.begin(), sq.end(), [](const Flight& l, const Flight& r) { return l.s > r.s; });
        int T = (int)target_times.size();
        sq_latest.assign(T, vector<vector<int>>(in.N, vector<int>(in.N, -1000000000)));
        for (int ti = 0; ti < T; ++ti) {
            for (int goal = 0; goal < in.N; ++goal) {
                sq_latest[ti][goal] = latest_departures(sq, goal, target_times[ti]);
            }
        }
    }

    void build_valid_pair() {
        valid_pair.assign(in.N, vector<char>(in.N, 0));
        const double th = 0.25 * in.R;
        for (int i = 0; i < in.N; ++i) {
            for (int j = 0; j < in.N; ++j) {
                valid_pair[i][j] = (hypot(double(in.x[i] - in.x[j]), double(in.y[i] - in.y[j])) >= th);
            }
        }
    }

    void repair_plane(vector<Flight>& p) {
        for (int i = 0; i < (int)p.size(); ++i) {
            if (i > 0) {
                p[i].a = p[i - 1].b;
                p[i].s = max(p[i].s, p[i - 1].t);
            }
            p[i].s = max(p[i].s, START_TIME);
            p[i].s = ceil5(p[i].s);
            if (p[i].a == p[i].b) p[i].b = (p[i].b + 1) % in.N;
            p[i].t = p[i].s + dur[p[i].a][p[i].b];
            if (p[i].s > END_TIME || p[i].t > END_TIME) {
                p.resize(i);
                return;
            }
        }
    }

    vector<vector<Flight>> build_initial() {
        vector<vector<Flight>> plans(in.K);

        vector<pair<int, int>> seeds = enemy_strong_pairs;
        if (seeds.empty()) {
            int hubs = min(6, (int)top_cities.size());
            for (int i = 0; i < hubs; ++i) {
                int a = top_cities[i];
                int b = top_cities[(i + 1) % hubs];
                if (a == b) b = (b + 1) % in.N;
                seeds.push_back({a, b});
            }
        }

        for (int k = 0; k < in.K; ++k) {
            auto [hub, dst] = seeds[k % (int)seeds.size()];
            int cur = START_TIME + (k % 4) * 5;
            while (true) {
                Flight f1{hub, cur, dst, 0};
                f1.t = f1.s + dur[f1.a][f1.b];
                if (f1.t > END_TIME) break;
                plans[k].push_back(f1);
                cur = f1.t;
                Flight f2{dst, cur, hub, 0};
                f2.t = f2.s + dur[f2.a][f2.b];
                if (f2.t > END_TIME) break;
                plans[k].push_back(f2);
                cur = f2.t;
            }
        }
        return plans;
    }

    EvalResult evaluate(const vector<vector<Flight>>& plans, double smooth_c, bool full_city) const {
        vector<Flight> all;
        all.reserve(800);
        for (const auto& p : plans) for (const auto& f : p) all.push_back(f);
        sort(all.begin(), all.end(), [](const Flight& l, const Flight& r) { return l.s > r.s; });

        vector<int> city_set;
        if (full_city) {
            city_set.resize(in.N);
            iota(city_set.begin(), city_set.end(), 0);
        } else {
            city_set = top_cities;
        }

        double smooth = 0.0;
        long long v_ci = 0, v_sq = 0;
        for (int ti = 0; ti < (int)target_times.size(); ++ti) {
            for (int goal : city_set) {
                vector<int> ci_latest = latest_departures(all, goal, target_times[ti]);
                const auto& sq = sq_latest[ti][goal];
                for (int i = 0; i < in.N; ++i) {
                    if (!valid_pair[i][goal]) continue;
                    long long w = 1LL * in.w[i] * in.w[goal];
                    int d = ci_latest[i] - sq[i];
                    if (d > 0) {
                        smooth += (double)w;
                        v_ci += w;
                    } else {
                        if (smooth_c > 1e-9) smooth += (double)w * exp((double)d / smooth_c);
                        v_sq += w;
                    }
                }
            }
        }
        long long binary = (v_ci + v_sq == 0) ? 0LL : (1000000LL * v_ci) / (v_ci + v_sq);
        return {smooth, binary};
    }

    void mutate(vector<vector<Flight>>& plans, int type) {
        int pid = rng.next_int(0, in.K - 1);
        auto& p = plans[pid];
        auto rand_city = [&]() { return top_cities[rng.next_int(0, (int)top_cities.size() - 1)]; };

        if (type == 0) {
            if (p.empty()) type = 2;
            else {
                int i = rng.next_int(0, (int)p.size() - 1);
                int d = (rng.next_int(0, 1) ? 5 : 10) * (rng.next_int(0, 1) ? 1 : -1);
                p[i].s = max(START_TIME, min(END_TIME, p[i].s + d));
            }
        }
        if (type == 1) {
            if (p.empty()) type = 2;
            else {
                int i = rng.next_int(0, (int)p.size() - 1);
                int nb = rand_city();
                if (nb == p[i].a) nb = (nb + 1) % in.N;
                p[i].b = nb;
            }
        }
        if (type == 2) {
            int pos = p.empty() ? 0 : rng.next_int(0, (int)p.size());
            Flight f{};
            if (pos == 0) {
                f.a = rand_city();
                f.s = START_TIME + 5 * rng.next_int(0, (END_TIME - START_TIME) / 5);
            } else {
                f.a = p[pos - 1].b;
                f.s = p[pos - 1].t;
            }
            f.b = rand_city();
            if (f.b == f.a) f.b = (f.b + 1) % in.N;
            f.t = f.s + dur[f.a][f.b];
            p.insert(p.begin() + pos, f);
        }
        if (type == 3) {
            if (!p.empty()) {
                int i = rng.next_int(0, (int)p.size() - 1);
                p.erase(p.begin() + i);
            }
        }
        repair_plane(p);
    }

    pair<long long, string> run() {
        vector<vector<Flight>> cur = build_initial();
        vector<vector<Flight>> best = cur;

        auto t0 = chrono::steady_clock::now();
        EvalResult cur_eval = evaluate(cur, SMOOTH_C_START, false);
        EvalResult best_eval = cur_eval;

        long long loops = 0;
        array<long long, 4> acc{}, tried{};
        double next_log = 0.1;

        while (true) {
            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t0).count();
            if (elapsed >= TL_SEC) break;
            double p = elapsed / TL_SEC;
            double temp = SA_TEMP_START * pow(SA_TEMP_END / SA_TEMP_START, p);
            double smooth_c = SMOOTH_C_START + (SMOOTH_C_END - SMOOTH_C_START) * p;
            bool full_city = (p > 0.88);

            int type = rng.next_int(0, 99);
            if (type < 50) type = 0;
            else if (type < 75) type = 1;
            else if (type < 90) type = 2;
            else type = 3;
            ++tried[type];

            auto nxt = cur;
            mutate(nxt, type);
            EvalResult nxt_eval = evaluate(nxt, smooth_c, full_city);

            double delta = nxt_eval.smooth_score - cur_eval.smooth_score;
            bool accept = false;
            if (delta >= 0.0) accept = true;
            else accept = (exp(delta / temp) > rng.next_double());

            if (accept) {
                ++acc[type];
                cur.swap(nxt);
                cur_eval = nxt_eval;
                if (cur_eval.smooth_score > best_eval.smooth_score) {
                    best = cur;
                    best_eval = cur_eval;
                }
            }
            ++loops;

            if (elapsed >= next_log) {
                cerr << fixed << setprecision(3)
                     << "t=" << elapsed
                     << " best_smooth=" << best_eval.smooth_score
                     << " acc=" << (tried[0] ? (double)acc[0] / tried[0] : 0.0) << ','
                     << (tried[1] ? (double)acc[1] / tried[1] : 0.0) << ','
                     << (tried[2] ? (double)acc[2] / tried[2] : 0.0) << ','
                     << (tried[3] ? (double)acc[3] / tried[3] : 0.0) << '\n';
                next_log += 0.1;
            }
        }

        EvalResult final_eval = evaluate(best, 0.0, true);

        ostringstream out;
        for (int k = 0; k < in.K; ++k) {
            out << best[k].size() << '\n';
            for (auto& f : best[k]) {
                out << (f.a + 1) << ' ' << fmt_time(f.s) << ' ' << (f.b + 1) << ' ' << fmt_time(f.t) << '\n';
            }
        }

        cerr << final_eval.binary_score << '\n';
        cerr << "TL=" << TL_SEC << " T0=" << SA_TEMP_START << " T1=" << SA_TEMP_END
             << " C0=" << SMOOTH_C_START << " C1=" << SMOOTH_C_END << '\n';
        cerr << "loops=" << loops << '\n';

        return {final_eval.binary_score, out.str()};
    }
};

pair<long long, string> solve(const Input& in) {
    Solver solver(in);
    return solver.run();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    Input in;
    string n_token;
    cin >> n_token >> in.R;
    if (n_token.size() >= 3 &&
        (unsigned char)n_token[0] == 0xEF &&
        (unsigned char)n_token[1] == 0xBB &&
        (unsigned char)n_token[2] == 0xBF) {
        n_token = n_token.substr(3);
    }
    in.N = stoi(n_token);
    in.x.resize(in.N);
    in.y.resize(in.N);
    in.w.resize(in.N);
    for (int i = 0; i < in.N; ++i) cin >> in.x[i] >> in.y[i] >> in.w[i];
    cin >> in.M;
    in.square.resize(in.M);
    for (int i = 0; i < in.M; ++i) {
        string ss, tt;
        cin >> in.square[i].a >> ss >> in.square[i].b >> tt;
        --in.square[i].a;
        --in.square[i].b;
        in.square[i].s = parse_time(ss);
        in.square[i].t = parse_time(tt);
    }
    cin >> in.K;

    auto [est, output] = solve(in);
    cout << output;
    return 0;
}
0