結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー tetra4
提出日時 2026-02-25 23:43:52
言語 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  
実行時間 991 ms / 1,000 ms
コード長 11,338 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 4,194 ms
コンパイル使用メモリ 361,008 KB
実行使用メモリ 7,912 KB
スコア 60,907,461
最終ジャッジ日時 2026-02-25 23:45:41
合計ジャッジ時間 107,572 ms
ジャッジサーバーID
(参考情報)
judge7 / judge2
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
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 = 2500;

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

// --- 便利ツール ---
string to_time_str(int t) {
    int h = 6 + t / 12, m = (t % 12) * 5;
    char buf[10];
    snprintf(buf, sizeof(buf), "%02d:%02d", h, m);
    return string(buf);
}
// 乱数生成器
class PCG32_Fast {
    uint64_t state_{0x853c49e6748fea9bull};
    static constexpr uint64_t MULT = 6364136223846793005ull;
    inline uint32_t next() {
        uint64_t x = state_;
        unsigned count = (unsigned)(x >> 61);
        state_ = x * MULT;
        x ^= x >> 22;
        return (uint32_t)(x >> (22 + count));
    }

   public:
    using result_type = uint32_t;
    static constexpr uint32_t min() {
        return 0;
    }
    static constexpr uint32_t max() {
        return 0xFFFFFFFF;
    }
    constexpr PCG32_Fast() = default;
    inline void seed(uint64_t seed) {
        state_ = 2 * seed + 1;
        next();
    }
    inline uint32_t operator()() {
        return next();
    }
    inline uint32_t uniform(uint32_t n) {
        return (uint32_t)((uint64_t)next() * n >> 32);
    }
    inline uint32_t uniform(uint32_t l, uint32_t r) {
        return l + uniform(r - l);
    }
    inline float uniform_float() {
        return (float)next() * 2.3283064365386963e-10f;
    }
    inline float uniform_float(float l, float r) {
        return l + uniform_float() * (r - l);
    }
};
inline PCG32_Fast RNG;

// タイマー
class Timer {
    chrono::steady_clock::time_point start_time_;

   public:
    Timer() : start_time_(chrono::steady_clock::now()) {}
    inline void reset() {
        start_time_ = chrono::steady_clock::now();
    }
    [[nodiscard]] inline float elapsed() const {
        auto now = chrono::steady_clock::now();
        return chrono::duration<float>(now - start_time_).count();
    }
    [[nodiscard]] inline bool is_exceeded(float limit) const {
        return elapsed() > limit;
    }
};
inline Timer TIMER;

// --- データ管理 ---
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;
    array<array<int, N>, N> dur;

    Input() {
        int _;
        cin >> _ >> _;
        for (int i = 0; i < N; ++i) cin >> x[i] >> y[i] >> w[i];
        int m_val;
        cin >> m_val;
        for (int i = 0; i < m_val; ++i) {
            string s_str, t_str;
            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], dy = y[i] - y[j];
                dur[i][j] = (int)ceil((60.0 * sqrt(dx * dx + dy * dy) / 800.0 + 40.0) / 5.0 - 1e-9);
                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;
                }
            }
        }
    }
};

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;
};

// 共通計算関数
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, 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);
            ws.reach[dst][T_target] = true;
            for (int t = T_target; t >= 0; --t) {
                for (int u = 0; u < N; ++u) {
                    if (t + 1 <= T_target && ws.reach[u][t + 1]) ws.reach[u][t] = true;
                    for (int e = ws.head[u][t]; e != -1; e = ws.nxt[e]) {
                        if (flights[e].t <= T_target && ws.reach[flights[e].v][flights[e].t])
                            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;
                    }
            }
        }
    }
}

// 辺の限界利益を計算し、最長路(最適パス)を一本見つける
vector<Flight> find_best_path(const Input& in, const array<array<array<int, 21>, N>, N>& rival_s_sq,
                              const array<array<array<int, 21>, N>, N>& current_s_ci,
                              MarginalGainWorkspace& mg_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 r_s = rival_s_sq[u][dst][T_idx], c_s = current_s_ci[u][dst][T_idx];
                if (c_s > r_s) continue;
                int min_s = max(0, r_s + 1), T_target = 60 + T_idx * 6;
                for (int v = 0; v < N; ++v) {
                    if (u == v) continue;
                    int max_t = (v == dst) ? T_target : current_s_ci[v][dst][T_idx];
                    if (max_t < 0) continue;
                    int max_s = min(180 - in.dur[u][v], max_t - in.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) {
            long long cur = 0;
            for (int s = 0; s <= 180; ++s) {
                cur += mg_ws.edge_gain[u][v][s];
                mg_ws.edge_gain[u][v][s] = cur;
            }
        }
    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 nt = t + in.dur[u][v];
                if (nt <= 180) {
                    long long g = mg_ws.edge_gain[u][v][t] + mg_ws.dp[v][nt];
                    if (g > mg_ws.dp[u][t]) {
                        mg_ws.dp[u][t] = g;
                        mg_ws.nxt_v[u][t] = v;
                    }
                }
            }
        }
    }
    int cur_u = 0;
    long long best_v = -1;
    for (int u = 0; u < N; ++u)
        if (mg_ws.dp[u][0] > best_v) {
            best_v = mg_ws.dp[u][0];
            cur_u = u;
        }
    vector<Flight> path;
    int cur_t = 0;
    while (cur_t <= 180) {
        int nv = mg_ws.nxt_v[cur_u][cur_t];
        if (nv != -1) {
            path.push_back({cur_u, cur_t, nv, cur_t + in.dur[cur_u][nv]});
            cur_t += in.dur[cur_u][nv];
            cur_u = nv;
        } else cur_t++;
    }
    return path;
}

long long get_score(const Input& in, const array<array<array<int, 21>, N>, N>& r_s,
                    const array<array<array<int, 21>, N>, N>& c_s) {
    long long v_ci = 0;
    for (int u = 0; u < N; ++u)
        for (int v = 0; v < N; ++v) {
            if (!in.valid_dist[u][v]) continue;
            for (int t = 0; t < 21; ++t)
                if (c_s[u][v][t] > r_s[u][v][t]) v_ci += in.weight[u][v];
        }
    return (long long)(1000000.0 * (double)v_ci / in.total_W);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    Input in;
    auto c_ws = make_unique<ComputeSciWorkspace>();
    auto mg_ws = make_unique<MarginalGainWorkspace>();

    array<array<array<int, 21>, N>, N> rival_s_sq;
    {
        vector<Flight> rf;
        rf.reserve(M);
        for (int i = 0; i < M; ++i) rf.push_back({in.a[i], in.s[i], in.b[i], in.t[i]});
        compute_s_ci(in, rf, rival_s_sq, *c_ws);
    }

    // 初期解: 逐次最長路
    array<vector<Flight>, K> current_paths;
    vector<Flight> all_flights;
    for (int k = 0; k < K; ++k) {
        array<array<array<int, 21>, N>, N> s_ci;
        compute_s_ci(in, all_flights, s_ci, *c_ws);
        current_paths[k] = find_best_path(in, rival_s_sq, s_ci, *mg_ws);
        for (auto& f : current_paths[k]) all_flights.push_back(f);
    }

    array<array<array<int, 21>, N>, N> current_s_ci;
    compute_s_ci(in, all_flights, current_s_ci, *c_ws);
    long long current_score = get_score(in, rival_s_sq, current_s_ci);

    // 破壊再構築
    int itr = 0;
    int acc = 0;
    while (TIMER.elapsed() < 0.95f) {
        int D = 1;
        array<int, K> idx;
        iota(idx.begin(), idx.end(), 0);
        shuffle(idx.begin(), idx.end(), RNG);

        auto backup_paths = current_paths;
        vector<Flight> remaining;
        for (int i = D; i < K; ++i)
            for (auto& f : current_paths[idx[i]]) remaining.push_back(f);

        vector<Flight> temp_all = remaining;
        for (int i = 0; i < D; ++i) {
            array<array<array<int, 21>, N>, N> s_ci_tmp;
            compute_s_ci(in, temp_all, s_ci_tmp, *c_ws);
            current_paths[idx[i]] = find_best_path(in, rival_s_sq, s_ci_tmp, *mg_ws);
            for (auto& f : current_paths[idx[i]]) temp_all.push_back(f);
        }

        array<array<array<int, 21>, N>, N> next_s_ci;
        compute_s_ci(in, temp_all, next_s_ci, *c_ws);
        long long next_score = get_score(in, rival_s_sq, next_s_ci);

        if (next_score >= current_score) {
            current_score = next_score;
            ++acc;
        } else {
            current_paths = backup_paths;
        }
        ++itr;
    }
    cerr << "Iteration : " << itr << "\n";
    cerr << "Accepted : " << acc << "\n";

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