結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー mogura3.0
提出日時 2026-02-25 23:59:12
言語 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  
実行時間 906 ms / 1,000 ms
コード長 14,651 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 4,280 ms
コンパイル使用メモリ 269,316 KB
実行使用メモリ 7,848 KB
スコア 44,237,313
最終ジャッジ日時 2026-02-26 00:02:19
合計ジャッジ時間 100,165 ms
ジャッジサーバーID
(参考情報)
judge7 / judge3
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <utility>
#include <vector>

using namespace std;

struct City {
    int x, y;
    long long w;
};

struct Flight {
    int u, v;   // 0-indexed cities
    int s, t;   // minutes from 00:00
};

struct PlanePlan {
    int spoke;      // 0-indexed city, must be != hub
    int phaseSlot;  // 0..11 => 0..55 minutes offset from 06:00
    bool startHub;
};

static constexpr int DAY_START = 6 * 60;      // 06:00
static constexpr int DAY_END = 21 * 60;       // 21:00
static constexpr int Q = 21;                  // 11:00..21:00 every 30 min
static constexpr int INF_NEG = -1'000'000'000;

int parse_time_token(const string& tok) {
    auto pos = tok.find(':');
    if (pos == string::npos) return stoi(tok);  // fallback
    int hh = stoi(tok.substr(0, pos));
    int mm = stoi(tok.substr(pos + 1));
    return hh * 60 + mm;
}

void print_time(int minute) {
    int hh = minute / 60;
    int mm = minute % 60;
    cout << setw(2) << setfill('0') << hh << ':'
         << setw(2) << setfill('0') << mm;
    cout << setfill(' ');
}

int calc_duration_minutes(const City& c1, const City& c2) {
    // Need exact 5-minute ceil of (3 * distance / 40 + 40).
    long long dx = (long long)c1.x - (long long)c2.x;
    long long dy = (long long)c1.y - (long long)c2.y;
    long long d2 = dx * dx + dy * dy;

    // Max possible distance <= 2000 => duration <= 190.
    for (int dur = 40; dur <= 300; dur += 5) {
        long long lhs = 40LL * dur - 1600LL;  // >= 0
        if (lhs * lhs >= 9LL * d2) return dur;
    }
    return 300;  // unreachable under constraints
}

struct Solver {
    int N = 0, R = 0;
    int M = 0, K = 0;
    vector<City> cities;
    vector<Flight> squareFlights;

    vector<vector<int>> dur;
    vector<vector<unsigned char>> eligible;
    vector<vector<unsigned long long>> pairW;
    unsigned __int128 denomWeight = 0;  // all eligible OD weights * Q

    array<int, Q> targetTimes{};
    vector<int> sqLatest;  // [q][dst][src] flattened

    vector<int> hubOrder;
    vector<vector<int>> spokeOrder;  // per hub, sorted candidates

    chrono::steady_clock::time_point t0;
    double internalTimeLimitSec = 0.90;  // deep-dive preset

    int idx3(int q, int dst, int src) const {
        return (q * N + dst) * N + src;
    }

    bool time_over() const {
        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t0).count();
        return elapsed >= internalTimeLimitSec;
    }

    void read_input() {
        cin >> N >> R;
        cities.resize(N);
        for (int i = 0; i < N; ++i) {
            cin >> cities[i].x >> cities[i].y >> cities[i].w;
        }

        cin >> M;
        squareFlights.reserve(M);
        for (int i = 0; i < M; ++i) {
            int a, b;
            string sTok, tTok;
            cin >> a >> sTok >> b >> tTok;
            int s = parse_time_token(sTok);
            int t = parse_time_token(tTok);
            squareFlights.push_back(Flight{a - 1, b - 1, s, t});
        }

        cin >> K;

        for (int q = 0; q < Q; ++q) targetTimes[q] = 11 * 60 + 30 * q;
    }

    void precompute_geometry() {
        dur.assign(N, vector<int>(N, 0));
        eligible.assign(N, vector<unsigned char>(N, 0));
        pairW.assign(N, vector<unsigned long long>(N, 0));

        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (i != j) dur[i][j] = calc_duration_minutes(cities[i], cities[j]);

                long long dx = (long long)cities[i].x - (long long)cities[j].x;
                long long dy = (long long)cities[i].y - (long long)cities[j].y;
                long long d2 = dx * dx + dy * dy;

                // distance >= 0.25R  <=>  16*d^2 >= R^2
                if (16LL * d2 >= 1LL * R * R) {
                    eligible[i][j] = 1;
                    pairW[i][j] = (unsigned long long)cities[i].w * (unsigned long long)cities[j].w;
                }
            }
        }

        unsigned __int128 oneQuery = 0;
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (eligible[i][j]) oneQuery += (unsigned __int128)pairW[i][j];
            }
        }
        denomWeight = oneQuery * (unsigned __int128)Q;
    }

    void precompute_orders() {
        vector<pair<long double, int>> hubs;
        hubs.reserve(N);
        spokeOrder.assign(N, {});

        for (int h = 0; h < N; ++h) {
            long double acc = 0.0L;
            vector<pair<long double, int>> cand;
            cand.reserve(max(0, N - 1));
            for (int v = 0; v < N; ++v) {
                if (v == h) continue;
                long double s = (long double)cities[v].w / (long double)dur[h][v];
                cand.push_back({s, v});
                acc += s;
            }
            sort(cand.begin(), cand.end(), [&](const auto& a, const auto& b) {
                if (a.first != b.first) return a.first > b.first;
                return a.second < b.second;
            });
            spokeOrder[h].reserve(cand.size());
            for (auto& p : cand) spokeOrder[h].push_back(p.second);

            long double hubScore = acc * (long double)cities[h].w;
            hubs.push_back({hubScore, h});
        }

        sort(hubs.begin(), hubs.end(), [&](const auto& a, const auto& b) {
            if (a.first != b.first) return a.first > b.first;
            return a.second < b.second;
        });
        hubOrder.clear();
        hubOrder.reserve(N);
        for (auto& p : hubs) hubOrder.push_back(p.second);
    }

    void precompute_square_latest() {
        vector<Flight> fs = squareFlights;
        sort(fs.begin(), fs.end(), [&](const Flight& a, const Flight& b) {
            if (a.s != b.s) return a.s > b.s;
            if (a.t != b.t) return a.t > b.t;
            if (a.u != b.u) return a.u < b.u;
            return a.v < b.v;
        });

        sqLatest.assign(Q * N * N, INF_NEG);
        vector<int> best(N);

        for (int q = 0; q < Q; ++q) {
            int T = targetTimes[q];
            for (int dst = 0; dst < N; ++dst) {
                fill(best.begin(), best.end(), INF_NEG);
                best[dst] = T;

                for (const auto& f : fs) {
                    if (best[f.v] >= f.t && best[f.u] < f.s) {
                        best[f.u] = f.s;
                    }
                }
                for (int src = 0; src < N; ++src) {
                    sqLatest[idx3(q, dst, src)] = best[src];
                }
            }
        }
    }

    vector<Flight> build_circle_flights(int hub, const vector<PlanePlan>& plans) const {
        vector<Flight> flights;
        flights.reserve(K * 16);

        for (int p = 0; p < K; ++p) {
            int spoke = plans[p].spoke;
            if (spoke == hub) continue;  // safety fallback

            int cur = plans[p].startHub ? hub : spoke;
            int tm = DAY_START + 5 * plans[p].phaseSlot;

            while (true) {
                int nxt = (cur == hub ? spoke : hub);
                int arr = tm + dur[cur][nxt];
                if (arr > DAY_END) break;
                flights.push_back(Flight{cur, nxt, tm, arr});
                cur = nxt;
                tm = arr;
            }
        }

        sort(flights.begin(), flights.end(), [&](const Flight& a, const Flight& b) {
            if (a.s != b.s) return a.s > b.s;
            if (a.t != b.t) return a.t > b.t;
            if (a.u != b.u) return a.u < b.u;
            return a.v < b.v;
        });
        return flights;
    }

    unsigned __int128 evaluate_vci(int hub, const vector<PlanePlan>& plans) const {
        vector<Flight> flights = build_circle_flights(hub, plans);
        vector<int> best(N);

        unsigned __int128 vci = 0;
        for (int q = 0; q < Q; ++q) {
            int T = targetTimes[q];
            for (int dst = 0; dst < N; ++dst) {
                fill(best.begin(), best.end(), INF_NEG);
                best[dst] = T;

                for (const auto& f : flights) {
                    if (best[f.v] >= f.t && best[f.u] < f.s) {
                        best[f.u] = f.s;
                    }
                }

                int base = (q * N + dst) * N;
                for (int src = 0; src < N; ++src) {
                    if (!eligible[src][dst]) continue;
                    if (sqLatest[base + src] < best[src]) {
                        vci += (unsigned __int128)pairW[src][dst];
                    }
                }
            }
        }
        return vci;
    }

    vector<PlanePlan> initial_plans_for_hub(int hub) const {
        vector<PlanePlan> plans(K);
        const auto& order = spokeOrder[hub];
        int m = (int)order.size();
        for (int p = 0; p < K; ++p) {
            plans[p].spoke = order[p % m];
            plans[p].phaseSlot = p % 12;
            plans[p].startHub = (p % 2 == 0);
        }
        return plans;
    }

    struct SearchResult {
        int hub = 0;
        vector<PlanePlan> plans;
        unsigned __int128 vci = 0;
    };

    SearchResult optimize_one_hub(int hub) {
        static constexpr int MAX_PASSES = 3;        // deep-dive preset
        static constexpr int SPOKE_CAND_LIMIT = 18; // deep-dive preset

        SearchResult res;
        res.hub = hub;
        res.plans = initial_plans_for_hub(hub);
        res.vci = evaluate_vci(hub, res.plans);

        bool any = true;
        for (int pass = 0; pass < MAX_PASSES && any && !time_over(); ++pass) {
            any = false;

            for (int p = 0; p < K; ++p) {
                if (time_over()) break;

                // 1) Spoke coordinate
                {
                    int curSpoke = res.plans[p].spoke;
                    int bestSpoke = curSpoke;
                    unsigned __int128 bestVal = res.vci;

                    int tried = 0;
                    for (int cand : spokeOrder[hub]) {
                        if (cand == hub || cand == curSpoke) continue;
                        res.plans[p].spoke = cand;
                        unsigned __int128 val = evaluate_vci(hub, res.plans);
                        if (val > bestVal) {
                            bestVal = val;
                            bestSpoke = cand;
                        }
                        ++tried;
                        if (tried >= SPOKE_CAND_LIMIT) break;
                        if ((tried & 3) == 0 && time_over()) break;
                    }

                    res.plans[p].spoke = bestSpoke;
                    if (bestVal > res.vci) {
                        res.vci = bestVal;
                        any = true;
                    }
                }

                if (time_over()) break;

                // 2) Phase coordinate (0..11 => 0..55 minutes)
                {
                    int curPhase = res.plans[p].phaseSlot;
                    int bestPhase = curPhase;
                    unsigned __int128 bestVal = res.vci;

                    for (int ph = 0; ph < 12; ++ph) {
                        if (ph == curPhase) continue;
                        res.plans[p].phaseSlot = ph;
                        unsigned __int128 val = evaluate_vci(hub, res.plans);
                        if (val > bestVal) {
                            bestVal = val;
                            bestPhase = ph;
                        }
                        if ((ph & 3) == 3 && time_over()) break;
                    }

                    res.plans[p].phaseSlot = bestPhase;
                    if (bestVal > res.vci) {
                        res.vci = bestVal;
                        any = true;
                    }
                }

                if (time_over()) break;

                // 3) Start direction coordinate
                {
                    bool curDir = res.plans[p].startHub;
                    bool bestDir = curDir;
                    unsigned __int128 bestVal = res.vci;

                    res.plans[p].startHub = !curDir;
                    unsigned __int128 val = evaluate_vci(hub, res.plans);
                    if (val > bestVal) {
                        bestVal = val;
                        bestDir = !curDir;
                    }

                    res.plans[p].startHub = bestDir;
                    if (bestVal > res.vci) {
                        res.vci = bestVal;
                        any = true;
                    }
                }
            }
        }

        return res;
    }

    SearchResult solve() {
        t0 = chrono::steady_clock::now();

        read_input();
        precompute_geometry();
        precompute_orders();
        precompute_square_latest();

        SearchResult bestAll;
        bool initialized = false;

        int hubTrials = min(N, 3);  // deep-dive preset
        for (int i = 0; i < hubTrials; ++i) {
            if (time_over()) break;
            int hub = hubOrder[i];
            SearchResult cand = optimize_one_hub(hub);
            if (!initialized || cand.vci > bestAll.vci) {
                bestAll = std::move(cand);
                initialized = true;
            }
        }

        if (!initialized) {
            int hub = hubOrder.empty() ? 0 : hubOrder[0];
            bestAll = optimize_one_hub(hub);
        }
        return bestAll;
    }

    void output_answer(const SearchResult& ans) const {
        // Rebuild grouped by plane for output in required format.
        vector<vector<Flight>> perPlane(K);
        for (int p = 0; p < K; ++p) {
            int spoke = ans.plans[p].spoke;
            if (spoke == ans.hub) continue;

            int cur = ans.plans[p].startHub ? ans.hub : spoke;
            int tm = DAY_START + 5 * ans.plans[p].phaseSlot;

            while (true) {
                int nxt = (cur == ans.hub ? spoke : ans.hub);
                int arr = tm + dur[cur][nxt];
                if (arr > DAY_END) break;
                perPlane[p].push_back(Flight{cur, nxt, tm, arr});
                cur = nxt;
                tm = arr;
            }
        }

        for (int p = 0; p < K; ++p) {
            cout << perPlane[p].size() << '\n';
            for (const auto& f : perPlane[p]) {
                cout << (f.u + 1) << ' ';
                print_time(f.s);
                cout << ' ' << (f.v + 1) << ' ';
                print_time(f.t);
                cout << '\n';
            }
        }
    }
};

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

    Solver solver;
    auto ans = solver.solve();
    solver.output_answer(ans);
    return 0;
}
0