// yukicoder No.5023 Airlines Optimization // Greedy by plane: build k-th plane route by DP on time-expanded graph, // where each flight-edge weight = (approx.) additional wins vs Square when ONLY that edge is added. // // Compile: g++ -O2 -std=c++17 -pipe -static -s main.cpp -o main #include using namespace std; static constexpr int MAXN = 47; static constexpr int SLOT_MIN = 5; static constexpr int DAY_START_MIN = 6 * 60; // 06:00 static constexpr int DAY_END_MIN = 21 * 60; // 21:00 static constexpr int TS = (DAY_END_MIN - DAY_START_MIN) / SLOT_MIN + 1; // 181 static constexpr int V = MAXN * TS; // ====== speed/quality knobs (heuristics) ====== static constexpr int ORIGIN_USE = 30; static constexpr int START_USE = 12; static constexpr int NEAR_CAND = 6; static constexpr int POP_CAND = 6; static constexpr int K_FIXED = 25; static constexpr int M_FIXED = 400; // Target arrival times: 11:00, 11:30, ..., 21:00 (21 values) static constexpr int TGT = 21; struct FlightOut { int a, b; // 0-based cities int dep_t; // time index int arr_t; // time index }; static inline int timeToIdx(int minute) { return (minute - DAY_START_MIN) / SLOT_MIN; } static inline int idxToTime(int idx) { return DAY_START_MIN + idx * SLOT_MIN; } static inline string fmtTimeIdx(int idx) { int m = idxToTime(idx); int hh = m / 60; int mm = m % 60; char buf[6]; snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); return string(buf); } static inline int parseTimeStr(const string& s) { int hh = (s[0]-'0')*10 + (s[1]-'0'); int mm = (s[3]-'0')*10 + (s[4]-'0'); return hh*60 + mm; } // ===== global buffers ===== static uint32_t popW[MAXN]; static int N, R; static int durSlot[MAXN][MAXN]; static double distMat[MAXN][MAXN]; static bool validPair[MAXN][MAXN]; static uint16_t earliestSq[MAXN][MAXN][TS]; static uint16_t earliestCi[MAXN][MAXN][TS]; static constexpr uint16_t INF16 = 65535; static int16_t latestSq[MAXN][MAXN][TS]; static int16_t latestCi[MAXN][MAXN][TS]; static int16_t s_sq[MAXN][MAXN][TGT]; static int16_t s_ci[MAXN][MAXN][TGT]; static uint64_t reachMask[V][TGT]; static bool oldWin[MAXN][MAXN][TGT]; static uint64_t flipMask[ORIGIN_USE][TGT][TS]; static int tgtIdx[TGT]; static int firstTiTime[TS]; // first target index whose deadline >= timeIdx, else TGT // ===== fast sumW(mask) with static tables ===== static uint64_t T0[1<<16]; static uint64_t T1[1<<16]; static uint64_t T2[1<<15]; static inline void buildWeightTables(const uint32_t* w) { // chunk0 bits 0..15 T0[0]=0; for (uint32_t m=1; m<(1u<<16); m++) { uint32_t b = __builtin_ctz(m); uint32_t pm = m & (m-1); T0[m] = T0[pm] + (uint64_t)w[b]; } // chunk1 bits 16..31 T1[0]=0; for (uint32_t m=1; m<(1u<<16); m++) { uint32_t b = __builtin_ctz(m); uint32_t pm = m & (m-1); T1[m] = T1[pm] + (uint64_t)w[16 + b]; } // chunk2 bits 32..46 (15 bits) T2[0]=0; for (uint32_t m=1; m<(1u<<15); m++) { uint32_t b = __builtin_ctz(m); uint32_t pm = m & (m-1); T2[m] = T2[pm] + (uint64_t)w[32 + b]; } } static inline uint64_t sumW_mask(uint64_t mask) { uint32_t a = (uint32_t)(mask & 0xFFFFull); uint32_t b = (uint32_t)((mask >> 16) & 0xFFFFull); uint32_t c = (uint32_t)((mask >> 32) & 0x7FFFull); // 15 bits return T0[a] + T1[b] + T2[c]; } // ===== adjacency list (fixed array) ===== template struct Adj { int head[V]; uint8_t to[MAXE]; uint8_t arr_t[MAXE]; int nxt[MAXE]; int ecnt; void init() { std::fill(head, head+V, -1); ecnt = 0; } inline void addEdge(int u, int v, int at) { to[ecnt] = (uint8_t)v; arr_t[ecnt] = (uint8_t)at; nxt[ecnt] = head[u]; head[u] = ecnt++; } }; static Adj sqAdj; static Adj<20000> ciAdj; // plenty // ===== Build earliest and latest arrays for a schedule ===== static void buildEarliestAndLatest(const int* head, const uint8_t* to, const uint8_t* arr_t, const int* nxt, uint16_t earliest[MAXN][MAXN][TS], int16_t latest[MAXN][MAXN][TS]) { // earliest for (int d=0; d=0; t--) { for (int c=0; c sq); } } } } static void buildFlipMaskForOrigins(const vector& originsUsed) { for (int oi=0; oi<(int)originsUsed.size(); oi++) { int o = originsUsed[oi]; (void)o; for (int ti=0; ti sq if (thr <= TS-1) addAt[thr] |= (1ull << d); } uint64_t cur=0; for (int s=0; s& originsUsed) { for (int u=0; u solveOnePlaneDP(const vector>& candDest, const vector& startCities) { static __int128 dp[V]; static int prevv[V]; const __int128 NEG = -((__int128)1<<120); for (int i=0;i bestVal) { bestVal=cur; bestVtx=u; } // wait if (t+1 < TS) { int v = u+1; if (cur > dp[v]) { dp[v]=cur; prevv[v]=u; } } // flights (candidate destinations only) - order preserved for (int j: candDest[c]) { int dt = durSlot[c][j]; int at = t + dt; if (at >= TS) continue; int v = j*TS + at; uint64_t g = edgeGainUV(u, v); __int128 nv = cur + (__int128)g; if (nv > dp[v]) { dp[v]=nv; prevv[v]=u; } } } } for (int u=0;u bestVal) { bestVal=dp[u]; bestVtx=u; } } vector revFlights; int cur = bestVtx; while (cur!=-1) { int p = prevv[cur]; if (p==-1) break; int pc = p/TS, pt = p%TS; int cc = cur/TS, ct = cur%TS; if (pc != cc) { revFlights.push_back(FlightOut{pc, cc, pt, ct}); } cur = p; } reverse(revFlights.begin(), revFlights.end()); return revFlights; } // ===== score evaluation (debug) ===== static long long evalScoreEstimate() { __int128 vci=0, vsq=0; for (int o=0;o sq) vci += ww; else vsq += ww; } } } if (vci+vsq==0) return 0; long double S = (long double)vci / (long double)(vci+vsq); long long score = (long long)floor(1e6L * S + 1e-12L); return score; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N >> R; vector xs(N), ys(N); for (int i=0;i> xs[i] >> ys[i] >> popW[i]; } for (int i=0;i= thr); if (i==j) durSlot[i][j]=0; else { double raw = 60.0 * d / 800.0 + 40.0; int q = (int)ceil(raw / 5.0 - 1e-12); int durMin = q * 5; durSlot[i][j] = durMin / 5; } } } buildWeightTables(popW); int M; cin >> M; sqAdj.init(); for (int k=0;k> a >> ss >> b >> tt; --a; --b; int s = timeToIdx(parseTimeStr(ss)); int t = timeToIdx(parseTimeStr(tt)); sqAdj.addEdge(a*TS + s, b, t); } int K; cin >> K; (void)K; ciAdj.init(); // Precompute Square: earliestSq, latestSq, s_sq buildEarliestAndLatest(sqAdj.head, sqAdj.to, sqAdj.arr_t, sqAdj.nxt, earliestSq, latestSq); buildTargetsFromLatest(latestSq, s_sq); // candidate destinations per city vector popOrder(N); iota(popOrder.begin(), popOrder.end(), 0); sort(popOrder.begin(), popOrder.end(), [&](int a,int b){ return popW[a]>popW[b]; }); vector> candDest(N); for (int i=0;i> near; near.reserve(N-1); for (int j=0;j cand; cand.reserve(NEAR_CAND + POP_CAND + 4); for (int k=0;k<(int)near.size() && (int)cand.size() startCities; for (int i=0;i originsUsed; for (int i=0;i> routes(K_FIXED); for (int plane=0; plane