結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー tetra4
提出日時 2026-02-25 23:28: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  
実行時間 591 ms / 1,000 ms
コード長 9,245 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,724 ms
コンパイル使用メモリ 353,156 KB
実行使用メモリ 7,848 KB
スコア 60,608,384
最終ジャッジ日時 2026-02-25 23:30:13
合計ジャッジ時間 64,608 ms
ジャッジサーバーID
(参考情報)
judge4 / judge7
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

constexpr int N = 47, R = 1000, M = 400, K = 25;
constexpr int INF = 1e9;
constexpr int MAX_TIME_SLOTS = 182;
constexpr int MAX_FLIGHTS = 2000;

struct Flight {
    int u, s, v, t;
};

// スロット(0~180)を "HH:MM" 形式の文字列に変換
string to_time_str(int t) {
    int h = 6 + t / 12;
    int m = (t % 12) * 5;
    char buf[6];
    snprintf(buf, sizeof(buf), "%02d:%02d", h, m);
    return string(buf);
}

struct Input {
    array<int, N> x, y, w;
    array<int, M> a, s, b, t;
    array<array<bool, N>, N> valid_dist{};
    array<array<long long, N>, N> weight{};
    long long total_W = 0;

    Input() {
        int _;
        cin >> _ >> _;
        for (int i = 0; i < N; ++i) cin >> x[i] >> y[i] >> w[i];
        cin >> _;
        string s_str, t_str;
        for (int i = 0; i < M; ++i) {
            cin >> a[i] >> s_str >> b[i] >> t_str;
            --a[i], --b[i];
            s[i] = (stoi(s_str.substr(0, 2)) - 6) * 12 + stoi(s_str.substr(3, 2)) / 5;
            t[i] = (stoi(t_str.substr(0, 2)) - 6) * 12 + stoi(t_str.substr(3, 2)) / 5;
        }

        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (i == j) continue;
                long long dx = x[i] - x[j];
                long long dy = y[i] - y[j];
                if (dx * dx + dy * dy >= (R * R) / 16) {
                    valid_dist[i][j] = true;
                    weight[i][j] = (long long)w[i] * w[j];
                    total_W += weight[i][j] * 21;
                }
            }
        }
    }

    int get_duration(int u, int v) const {
        double dx = x[u] - x[v];
        double dy = y[u] - y[v];
        double d = sqrt(dx * dx + dy * dy);
        double minutes = 60.0 * d / 800.0 + 40.0;
        return (int)ceil(minutes / 5.0 - 1e-9);
    }
};

// 計算用のワークスペース
struct ComputeSciWorkspace {
    array<array<int, MAX_TIME_SLOTS>, N> head;
    array<int, MAX_FLIGHTS> nxt;
    array<array<bool, MAX_TIME_SLOTS>, N> reach;
};

// 限界利益探索用の巨大配列を保持するワークスペース
struct MarginalGainWorkspace {
    array<array<array<int, 21>, N>, N> current_s_ci;
    array<array<array<long long, MAX_TIME_SLOTS>, N>, N> edge_gain;
    array<array<long long, MAX_TIME_SLOTS>, N> dp;
    array<array<int, MAX_TIME_SLOTS>, N> nxt_v;
    array<array<int, N>, N> dur;
};

// 共通関数:フライト集合に対する限界出発時刻 (s_ci) を計算する
void compute_s_ci(const Input& in, const vector<Flight>& flights,
                  array<array<array<int, 21>, N>, N>& s_ci, ComputeSciWorkspace& ws) {
    for (int u = 0; u < N; ++u) {
        for (int dst = 0; dst < N; ++dst) {
            s_ci[u][dst].fill(-INF);
        }
    }

    for (int u = 0; u < N; ++u) ws.head[u].fill(-1);
    ws.nxt.fill(-1);

    for (int i = 0; i < (int)flights.size(); ++i) {
        int u = flights[i].u;
        int s = flights[i].s;
        ws.nxt[i] = ws.head[u][s];
        ws.head[u][s] = i;
    }

    for (int dst = 0; dst < N; ++dst) {
        for (int T_idx = 0; T_idx < 21; ++T_idx) {
            int T_target = 60 + T_idx * 6;
            for (int u = 0; u < N; ++u) ws.reach[u].fill(false);
            for (int t = 0; t <= T_target; ++t) ws.reach[dst][t] = true;

            for (int t = T_target; t >= 0; --t) {
                for (int u = 0; u < N; ++u) {
                    if (t + 1 <= 180 && ws.reach[u][t + 1]) ws.reach[u][t] = true;
                    for (int e = ws.head[u][t]; e != -1; e = ws.nxt[e]) {
                        int v = flights[e].v;
                        int arr_time = flights[e].t;
                        if (arr_time <= T_target && ws.reach[v][arr_time]) {
                            ws.reach[u][t] = true;
                        }
                    }
                }
            }
            for (int u = 0; u < N; ++u) {
                if (u == dst || !in.valid_dist[u][dst]) continue;
                for (int t = T_target; t >= 0; --t) {
                    if (ws.reach[u][t]) {
                        s_ci[u][dst][T_idx] = t;
                        break;
                    }
                }
            }
        }
    }
}

struct RivalSchedule {
    array<array<array<int, 21>, N>, N> s_sq;
    RivalSchedule(const Input& in, ComputeSciWorkspace& ws) {
        vector<Flight> r_flights;
        r_flights.reserve(M);
        for (int i = 0; i < M; ++i) r_flights.push_back({in.a[i], in.s[i], in.b[i], in.t[i]});
        compute_s_ci(in, r_flights, s_sq, ws);
    }
};

// 限界利益(Marginal Gain)に基づく逐次最長路アルゴリズム
array<vector<Flight>, K> solve_marginal_gain(const Input& in, const RivalSchedule& rival,
                                             ComputeSciWorkspace& c_ws,
                                             MarginalGainWorkspace& mg_ws) {
    array<vector<Flight>, K> circle_flights;
    vector<Flight> all_my_flights;
    all_my_flights.reserve(MAX_FLIGHTS);

    for (int u = 0; u < N; ++u) {
        for (int v = 0; v < N; ++v) {
            mg_ws.dur[u][v] = (u != v) ? in.get_duration(u, v) : 0;
        }
    }

    for (int k = 0; k < K; ++k) {
        compute_s_ci(in, all_my_flights, mg_ws.current_s_ci, c_ws);

        for (int u = 0; u < N; ++u) {
            for (int v = 0; v < N; ++v) mg_ws.edge_gain[u][v].fill(0);
        }

        for (int u = 0; u < N; ++u) {
            for (int dst = 0; dst < N; ++dst) {
                if (!in.valid_dist[u][dst]) continue;
                for (int T_idx = 0; T_idx < 21; ++T_idx) {
                    int s_sq_val = rival.s_sq[u][dst][T_idx];
                    int s_ci_val = mg_ws.current_s_ci[u][dst][T_idx];
                    if (s_ci_val > s_sq_val) continue;

                    int min_s = max(0, s_sq_val + 1);
                    int T_target = 60 + T_idx * 6;

                    for (int v = 0; v < N; ++v) {
                        if (u == v) continue;
                        int max_t = (v == dst) ? T_target : mg_ws.current_s_ci[v][dst][T_idx];
                        if (max_t < 0) continue;
                        int max_s = min(180 - mg_ws.dur[u][v], max_t - mg_ws.dur[u][v]);

                        if (min_s <= max_s) {
                            mg_ws.edge_gain[u][v][min_s] += in.weight[u][dst];
                            if (max_s + 1 <= 180)
                                mg_ws.edge_gain[u][v][max_s + 1] -= in.weight[u][dst];
                        }
                    }
                }
            }
        }

        for (int u = 0; u < N; ++u) {
            for (int v = 0; v < N; ++v) {
                if (u == v) continue;
                long long current_val = 0;
                for (int s = 0; s <= 180; ++s) {
                    current_val += mg_ws.edge_gain[u][v][s];
                    mg_ws.edge_gain[u][v][s] = current_val;
                }
            }
        }

        for (int u = 0; u < N; ++u) {
            mg_ws.dp[u].fill(0);
            mg_ws.nxt_v[u].fill(-1);
        }

        for (int t = 180; t >= 0; --t) {
            for (int u = 0; u < N; ++u) {
                if (t + 1 <= 180) {
                    mg_ws.dp[u][t] = mg_ws.dp[u][t + 1];
                    mg_ws.nxt_v[u][t] = -1;
                }
                for (int v = 0; v < N; ++v) {
                    if (u == v) continue;
                    int t_next = t + mg_ws.dur[u][v];
                    if (t_next <= 180) {
                        long long gain = mg_ws.edge_gain[u][v][t];
                        if (gain + mg_ws.dp[v][t_next] > mg_ws.dp[u][t]) {
                            mg_ws.dp[u][t] = gain + mg_ws.dp[v][t_next];
                            mg_ws.nxt_v[u][t] = v;
                        }
                    }
                }
            }
        }

        long long best_start_val = -1;
        int start_u = 0;
        for (int u = 0; u < N; ++u) {
            if (mg_ws.dp[u][0] > best_start_val) {
                best_start_val = mg_ws.dp[u][0];
                start_u = u;
            }
        }

        int curr_u = start_u, curr_t = 0;
        while (curr_t <= 180) {
            int next_city = mg_ws.nxt_v[curr_u][curr_t];
            if (next_city != -1) {
                int d = mg_ws.dur[curr_u][next_city];
                Flight f = {curr_u, curr_t, next_city, curr_t + d};
                circle_flights[k].push_back(f);
                all_my_flights.push_back(f);
                curr_u = next_city;
                curr_t += d;
            } else {
                curr_t += 1;
            }
        }
    }
    return circle_flights;
}

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

    Input in;
    auto c_ws = make_unique<ComputeSciWorkspace>();
    auto mg_ws = make_unique<MarginalGainWorkspace>();

    RivalSchedule rival(in, *c_ws);
    auto circle_flights = solve_marginal_gain(in, rival, *c_ws, *mg_ws);

    for (int k = 0; k < K; ++k) {
        cout << circle_flights[k].size() << "\n";
        for (const auto& f : circle_flights[k]) {
            cout << f.u + 1 << " " << to_time_str(f.s) << " " << f.v + 1 << " " << to_time_str(f.t)
                 << "\n";
        }
    }
    return 0;
}
0