結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー ぴぃいいいい
提出日時 2026-03-01 01:42: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
結果
TLE  
実行時間 -
コード長 17,618 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,660 ms
コンパイル使用メモリ 376,464 KB
実行使用メモリ 9,856 KB
スコア 58,067,996
最終ジャッジ日時 2026-03-01 01:44:25
合計ジャッジ時間 95,984 ms
ジャッジサーバーID
(参考情報)
judge3 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 98 TLE * 2
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

static constexpr int DL = 21;     // deadlines count
static constexpr int T  = 181;    // 06:00..21:00 in 5-min steps (inclusive)
static constexpr int CH0 = 16, CH1 = 16, CH2 = 15;

struct Edge {
    uint8_t to;
    uint8_t arr;
};

struct PlanFlight {
    int from, dep, to, arr;
};

static inline int parse_time_idx(const string& s) {
    int hh = (s[0]-'0')*10 + (s[1]-'0');
    int mm = (s[3]-'0')*10 + (s[4]-'0');
    int minutes = hh*60 + mm;
    return (minutes - 360) / 5; // 06:00=360
}

static inline string fmt_time_idx(int idx) {
    int minutes = 360 + idx*5;
    int hh = minutes / 60;
    int mm = minutes % 60;
    ostringstream oss;
    oss << setw(2) << setfill('0') << hh << ":" << setw(2) << setfill('0') << mm;
    return oss.str();
}

// duration in 5-min steps: ceil((40 + 60*d/800)/5)
static inline int calc_dur_steps(long double dx, long double dy) {
    long double d = sqrtl(dx*dx + dy*dy);
    long double raw = 40.0L + (60.0L * d) / 800.0L;
    long double v = raw / 5.0L;
    int steps = (int)ceill(v - 1e-12L);
    return max(0, steps);
}

// --------- 47-bit weight sum by chunk lookup ----------
struct WeightSum47 {
    vector<long long> sum0, sum1, sum2; // 2^16,2^16,2^15
    vector<long long> w;

    explicit WeightSum47(const vector<long long>& w_) : w(w_) {
        sum0.assign(1u<<CH0, 0);
        sum1.assign(1u<<CH1, 0);
        sum2.assign(1u<<CH2, 0);

        for (uint32_t m = 1; m < (1u<<CH0); m++) {
            uint32_t lsb = m & -m;
            uint32_t pm  = m ^ lsb;
            int b = __builtin_ctz(lsb);
            sum0[m] = sum0[pm] + w[b];
        }
        for (uint32_t m = 1; m < (1u<<CH1); m++) {
            uint32_t lsb = m & -m;
            uint32_t pm  = m ^ lsb;
            int b = __builtin_ctz(lsb);
            sum1[m] = sum1[pm] + w[CH0 + b];
        }
        for (uint32_t m = 1; m < (1u<<CH2); m++) {
            uint32_t lsb = m & -m;
            uint32_t pm  = m ^ lsb;
            int b = __builtin_ctz(lsb);
            sum2[m] = sum2[pm] + w[CH0 + CH1 + b];
        }
    }

    inline long long sum(uint64_t mask47) const {
        uint32_t m0 = (uint32_t)(mask47 & 0xFFFFULL);
        uint32_t m1 = (uint32_t)((mask47 >> 16) & 0xFFFFULL);
        uint32_t m2 = (uint32_t)((mask47 >> 32) & 0x7FFFULL);
        return sum0[m0] + sum1[m1] + sum2[m2];
    }
};

// --------- compute square latest depart (forward DP, from scratch) ----------
static void compute_latest_all_origins(
    int N,
    const vector<vector<Edge>>& outFlights, // size nodes = N*T
    vector<int16_t>& latest                 // size N*nodes
) {
    int nodes = N * T;
    latest.assign(N * nodes, (int16_t)-1);

    for (int o = 0; o < N; o++) {
        int16_t* dp = latest.data() + o * nodes;
        // can "start" at origin at any time t with departure time t
        for (int t = 0; t < T; t++) dp[o*T + t] = (int16_t)t;

        for (int t = 0; t < T; t++) {
            for (int c = 0; c < N; c++) {
                int node = c*T + t;
                int16_t val = dp[node];
                if (val < 0) continue;

                // wait
                if (t+1 < T) {
                    int node2 = node + 1; // same city, next time
                    if (val > dp[node2]) dp[node2] = val;
                }

                // flights
                for (const auto& e : outFlights[node]) {
                    int node3 = (int)e.to * T + (int)e.arr;
                    if (val > dp[node3]) dp[node3] = val;
                }
            }
        }
    }
}

// --------- incremental update for circle latest depart (difference update) ----------
static void relax_add_flights_incremental(
    int N,
    vector<vector<Edge>>& outCi,        // updated adjacency
    vector<int16_t>& ciLatest,          // size N*nodes, updated in-place
    const vector<PlanFlight>& added     // flights just added (for init relax)
) {
    int nodes = N * T;

    // queue buffers reused per origin (no reallocation inside loops)
    vector<int> q(nodes);
    vector<uint8_t> inq(nodes);

    for (int o = 0; o < N; o++) {
        int16_t* dp = ciLatest.data() + o * nodes;
        fill(inq.begin(), inq.end(), 0);
        int qh = 0, qt = 0;

        // initial relax only at the newly added edges
        for (const auto& f : added) {
            int fromNode = f.from*T + f.dep;
            int toNode   = f.to*T   + f.arr;
            int16_t val = dp[fromNode];
            if (val > dp[toNode]) {
                dp[toNode] = val;
                if (!inq[toNode]) {
                    inq[toNode] = 1;
                    q[qt++] = toNode;
                }
            }
        }

        // propagate improvements forward in time via wait + existing flights
        while (qh < qt) {
            int node = q[qh++];
            inq[node] = 0;

            int c = node / T;
            int t = node % T;
            int16_t val = dp[node];

            // wait
            if (t+1 < T) {
                int node2 = node + 1;
                if (val > dp[node2]) {
                    dp[node2] = val;
                    if (!inq[node2]) {
                        inq[node2] = 1;
                        q[qt++] = node2;
                    }
                }
            }

            // flights
            for (const auto& e : outCi[node]) {
                int node3 = (int)e.to * T + (int)e.arr;
                if (val > dp[node3]) {
                    dp[node3] = val;
                    if (!inq[node3]) {
                        inq[node3] = 1;
                        q[qt++] = node3;
                    }
                }
            }
        }
    }
}

// --------- reachDest[node][k] : destinations reachable from node by deadline[k] (including transfers) ----------
static void compute_reach_dest(
    int N,
    const array<int,DL>& deadlines,
    const vector<vector<Edge>>& outCi,      // circle schedule flights
    vector<uint64_t>& reachDest             // size nodes*DL
) {
    int nodes = N * T;
    reachDest.assign((size_t)nodes * DL, 0);

    vector<uint64_t> tmp(nodes, 0); // reused per deadline

    for (int k = 0; k < DL; k++) {
        int lim = deadlines[k];
        fill(tmp.begin(), tmp.end(), 0);

        for (int t = lim; t >= 0; --t) {
            for (int c = 0; c < N; c++) {
                int node = c*T + t;
                uint64_t val = 0;

                // wait
                if (t < lim) val |= tmp[node + 1];

                // stay => can reach destination "c" by deadline
                val |= (1ULL << c);

                // flights
                for (const auto& e : outCi[node]) {
                    if ((int)e.arr <= lim) {
                        int node2 = (int)e.to * T + (int)e.arr;
                        val |= tmp[node2];
                    }
                }

                tmp[node] = val;
            }
        }

        // store for all nodes (t<=lim); others remain 0
        for (int c = 0; c < N; c++) {
            for (int t = 0; t <= lim; t++) {
                int node = c*T + t;
                reachDest[(size_t)node * DL + k] = tmp[node];
            }
        }
    }
}

// --------- GoodDest[(o,cand),k] : destinations d where (ci<=sq) AND (sq < cand) AND eligible(o,d) ----------
static void compute_good_dest(
    int N,
    const array<int,DL>& deadlines,
    const vector<char>& eligibleOD,          // size N*N
    const vector<int16_t>& ciLatest,         // size N*nodes
    const vector<int16_t>& sqDeadline,       // size (N*N*DL)
    vector<uint64_t>& goodDest               // size (N*T*DL), index ((o*T+cand)*DL + k)
) {
    int nodes = N * T;
    goodDest.assign((size_t)N * T * DL, 0);

    // local bucket (on stack) to avoid heap alloc
    array<uint64_t, T> adds;

    for (int o = 0; o < N; o++) {
        const int16_t* dp = ciLatest.data() + o * nodes;

        for (int k = 0; k < DL; k++) {
            adds.fill(0);
            uint64_t base = 0;

            int limT = deadlines[k];

            for (int d = 0; d < N; d++) {
                if (d == o) continue;
                int od = o*N + d;
                if (!eligibleOD[od]) continue;

                int16_t ci = dp[d*T + limT];
                int16_t sq = sqDeadline[(od*DL) + k];

                // losing or tie: ci <= sq
                if (ci <= sq) {
                    if (sq < 0) {
                        base |= (1ULL << d);
                    } else {
                        int idx = (int)sq + 1; // include when cand >= sq+1  <=> sq < cand
                        if (idx < T) adds[idx] |= (1ULL << d);
                    }
                }
            }

            uint64_t cur = base;
            for (int cand = 0; cand < T; cand++) {
                cur |= adds[cand];
                goodDest[((size_t)o * T + cand) * DL + k] = cur;
            }
        }
    }
}

// --------- edge weight: (u,t)->(v,t2) considering transfers after arrival ----------
static inline __int128 edge_weight(
    int N,
    const WeightSum47& wsum,
    const vector<long long>& w,
    const vector<int16_t>& ciLatest,     // size N*nodes
    const vector<uint64_t>& reachDest,   // size nodes*DL
    const vector<uint64_t>& goodDest,    // size (N*T*DL)
    int u, int t, int v, int t2
) {
    int nodes = N * T;
    const uint64_t* reachPtr = &reachDest[(size_t)(v*T + t2) * DL];

    __int128 total = 0;

    for (int o = 0; o < N; o++) {
        const int16_t* dp = ciLatest.data() + (size_t)o * nodes;
        int16_t cand = dp[u*T + t];
        if (cand < 0) continue;

        const uint64_t* goodPtr = &goodDest[((size_t)o * T + (int)cand) * DL];

        long long sumWdest = 0;
        // DL=21 fixed small loop
        for (int k = 0; k < DL; k++) {
            uint64_t m = reachPtr[k] & goodPtr[k];
            sumWdest += wsum.sum(m);
        }

        total += (__int128)w[o] * (__int128)sumWdest;
    }

    return total;
}

static inline string to_string_i128(__int128 x) {
    if (x == 0) return "0";
    bool neg = false;
    if (x < 0) { neg = true; x = -x; }
    string s;
    while (x > 0) {
        int digit = (int)(x % 10);
        s.push_back('0' + digit);
        x /= 10;
    }
    if (neg) s.push_back('-');
    reverse(s.begin(), s.end());
    return s;
}

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

    int N;
    long long R;
    cin >> N >> R;

    vector<long long> x(N), y(N), w(N);
    for (int i = 0; i < N; i++) cin >> x[i] >> y[i] >> w[i];

    // deadlines: 11:00, 11:30, ..., 21:00
    array<int,DL> deadlines{};
    for (int k = 0; k < DL; k++) deadlines[k] = 60 + 6*k;

    // duration matrix
    vector<int> dur(N*N, 0);
    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (i != j) {
        long double dx = (long double)x[i] - (long double)x[j];
        long double dy = (long double)y[i] - (long double)y[j];
        dur[i*N + j] = calc_dur_steps(dx, dy);
    }

    // eligible OD: dist >= 0.25R
    long double thr = 0.25L * (long double)R;
    long double thr2 = thr * thr;
    vector<char> eligibleOD(N*N, 0);
    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (i != j) {
        long double dx = (long double)x[i] - (long double)x[j];
        long double dy = (long double)y[i] - (long double)y[j];
        long double d2 = dx*dx + dy*dy;
        if (d2 + 1e-12L >= thr2) eligibleOD[i*N + j] = 1;
    }

    int M;
    cin >> M;

    int nodes = N * T;
    vector<vector<Edge>> outSq(nodes), outCi(nodes);

    // read square flights; also trust input duration if slight mismatch
    for (int i = 0; i < M; i++) {
        int a, b;
        string ss, ts;
        cin >> a >> ss >> b >> ts;
        --a; --b;
        int dep = parse_time_idx(ss);
        int arr = parse_time_idx(ts);
        if (dep < 0 || dep >= T || arr < 0 || arr >= T) continue;
        // fix dur if needed
        if (dep + dur[a*N + b] != arr) dur[a*N + b] = arr - dep;
        outSq[a*T + dep].push_back(Edge{(uint8_t)b, (uint8_t)arr});
    }

    int K;
    cin >> K;

    // candidate destinations per city (pruning for speed)
    // 近いNEAR個 + 人口上位TOP個 を候補に
    const int NEAR = 8;
    const int TOP  = 4;
    vector<vector<int>> candTo(N);

    // precompute order by population
    vector<int> popOrder(N);
    iota(popOrder.begin(), popOrder.end(), 0);
    sort(popOrder.begin(), popOrder.end(), [&](int a, int b){ return w[a] > w[b]; });

    for (int i = 0; i < N; i++) {
        vector<pair<long double,int>> ds;
        ds.reserve(N-1);
        for (int j = 0; j < N; j++) if (j != i) {
            long double dx = (long double)x[i] - (long double)x[j];
            long double dy = (long double)y[i] - (long double)y[j];
            ds.push_back({dx*dx + dy*dy, j});
        }
        sort(ds.begin(), ds.end());
        vector<int> v;
        v.reserve(NEAR + TOP);

        // nearest
        for (int k = 0; k < (int)ds.size() && (int)v.size() < NEAR; k++) {
            v.push_back(ds[k].second);
        }
        // top-pop
        for (int idx : popOrder) {
            if (idx == i) continue;
            bool exists = false;
            for (int t : v) if (t == idx) { exists = true; break; }
            if (!exists) v.push_back(idx);
            if ((int)v.size() >= NEAR + TOP) break;
        }
        candTo[i] = move(v);
    }

    // square latest depart
    vector<int16_t> sqLatest;
    compute_latest_all_origins(N, outSq, sqLatest);

    // sqDeadline[od*DL + k]
    vector<int16_t> sqDeadline((size_t)N*N*DL, -1);
    for (int o = 0; o < N; o++) {
        const int16_t* dp = sqLatest.data() + (size_t)o * nodes;
        for (int d = 0; d < N; d++) if (d != o) {
            int od = o*N + d;
            for (int k = 0; k < DL; k++) {
                int lim = deadlines[k];
                sqDeadline[(size_t)od*DL + k] = dp[d*T + lim];
            }
        }
    }

    // circle latest depart (incremental)
    vector<int16_t> ciLatest((size_t)N * nodes, (int16_t)-1);
    for (int o = 0; o < N; o++) {
        int16_t* dp = ciLatest.data() + (size_t)o * nodes;
        // start at origin at any time
        for (int t = 0; t < T; t++) dp[o*T + t] = (int16_t)t;
    }

    WeightSum47 wsum(w);

    vector<uint64_t> reachDest; // nodes*DL
    vector<uint64_t> goodDest;  // (N*T*DL)

    vector<vector<PlanFlight>> answer(K);

    // DP buffers for route search
    vector<__int128> best(nodes);
    vector<int> parent(nodes);
    vector<uint8_t> ptype(nodes); // 1=wait,2=travel

    for (int plane = 0; plane < K; plane++) {
        // rebuild reachDest for current baseline schedule (transfers included)
        compute_reach_dest(N, deadlines, outCi, reachDest);

        // rebuild GoodDest for current baseline vs square
        compute_good_dest(N, deadlines, eligibleOD, ciLatest, sqDeadline, goodDest);

        // longest path DP on time-expanded graph
        const __int128 NEG = -((__int128)1 << 120);
        fill(best.begin(), best.end(), NEG);
        fill(parent.begin(), parent.end(), -1);
        fill(ptype.begin(), ptype.end(), 0);

        // allow start anywhere at 06:00 (time=0)
        for (int c = 0; c < N; c++) best[c*T + 0] = 0;

        for (int t = 0; t < T-1; t++) {
            for (int u = 0; u < N; u++) {
                int node = u*T + t;
                __int128 cur = best[node];
                if (cur <= NEG/2) continue;

                // wait
                int nodeW = node + 1;
                if (cur > best[nodeW]) {
                    best[nodeW] = cur;
                    parent[nodeW] = node;
                    ptype[nodeW] = 1;
                }

                // travel edges (pruned candidates)
                for (int v : candTo[u]) {
                    int dt = dur[u*N + v];
                    int t2 = t + dt;
                    if (t2 >= T) continue;

                    __int128 wEdge = edge_weight(N, wsum, w, ciLatest, reachDest, goodDest, u, t, v, t2);
                    int node2 = v*T + t2;
                    __int128 nv = cur + wEdge;
                    if (nv > best[node2]) {
                        best[node2] = nv;
                        parent[node2] = node;
                        ptype[node2] = 2;
                    }
                }
            }
        }

        // choose best at 21:00 (time = T-1)
        int bestNode = 0*T + (T-1);
        for (int c = 1; c < N; c++) {
            int node = c*T + (T-1);
            if (best[node] > best[bestNode]) bestNode = node;
        }

        // reconstruct flights
        vector<PlanFlight> flights;
        int curNode = bestNode;
        while (parent[curNode] != -1) {
            int p = parent[curNode];
            if (ptype[curNode] == 2) {
                int vc = curNode / T, vt = curNode % T;
                int uc = p / T, ut = p % T;
                flights.push_back(PlanFlight{uc, ut, vc, vt});
            }
            curNode = p;
        }
        reverse(flights.begin(), flights.end());
        answer[plane] = flights;

        // add to circle schedule + incremental update of ciLatest
        for (const auto& f : flights) {
            outCi[f.from*T + f.dep].push_back(Edge{(uint8_t)f.to, (uint8_t)f.arr});
        }
        relax_add_flights_incremental(N, outCi, ciLatest, flights);
    }

    // output
    for (int i = 0; i < K; i++) {
        cout << answer[i].size() << "\n";
        for (auto &f : answer[i]) {
            cout << (f.from + 1) << " " << fmt_time_idx(f.dep) << " "
                 << (f.to   + 1) << " " << fmt_time_idx(f.arr) << "\n";
        }
    }
    return 0;
}
0