제출 #1281238

#제출 시각아이디문제언어결과실행 시간메모리
1281238tunademayoMarathon Race 2 (JOI24_ho_t3)C++20
0 / 100
0 ms332 KiB
#include <bits/stdc++.h> using namespace std; using ll = long long; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int N; long long L; if (!(cin >> N >> L)) return 0; vector<long long> X(N); for (int i = 0; i < N; ++i) cin >> X[i]; // compress map<long long,int> mp; for (auto x : X) mp[x]++; vector<long long> pos; vector<int> cnts; for (auto &p : mp){ pos.push_back(p.first); cnts.push_back(p.second); } int M = pos.size(); auto simulate_with_defer = [&](long long S, long long G, bool goLeftFirst, int defer_idx)-> long long { // defer_idx: -1 means no defer; otherwise index in [0..M-1] to defer first time // build initial visit order (first sweep to one side then to other) vector<int> left_idx, right_idx; for (int i = 0; i < M; ++i){ if (pos[i] <= S) left_idx.push_back(i); else right_idx.push_back(i); } vector<int> visit; if (goLeftFirst){ for (int i = (int)left_idx.size()-1; i >= 0; --i) visit.push_back(left_idx[i]); for (int i = 0; i < (int)right_idx.size(); ++i) visit.push_back(right_idx[i]); } else { for (int i = 0; i < (int)right_idx.size(); ++i) visit.push_back(right_idx[i]); for (int i = (int)left_idx.size()-1; i >= 0; --i) visit.push_back(left_idx[i]); } // We'll simulate step-by-step. When moving from curPos to nextP, we will stop // at any not-yet-picked positions that lie between curPos and nextP (inclusive), // in the correct order along that direction. ll time = 0; ll curPos = S; int carrying = 0; vector<int> picked(M, 0); // Note: we do NOT auto-pick at S at time 0 unless S is explicitly visited in `visit` // and not deferred. auto process_move_to = [&](long long target){ // Move from curPos to target, but stop at any pos[k] lying strictly between curPos and target if (curPos == target) return; if (curPos < target){ // moving right; consider all positions with curPos < pos[i] && pos[i] <= target // Gather those indices sorted increasing by position vector<int> mids; for (int i = 0; i < M; ++i){ if (!picked[i] && pos[i] > curPos && pos[i] <= target) mids.push_back(i); } sort(mids.begin(), mids.end(), [&](int a, int b){ return pos[a] < pos[b]; }); ll from = curPos; for (int idx : mids){ ll to = pos[idx]; ll dist = to - from; time += dist * ( (ll)carrying + 1 ); // movement cost // when we arrive at pos[idx], decide whether to pick now: // pick if idx != defer_idx OR (idx==defer_idx AND this is not the first pass). // To know if this is "first pass", we mark defer by not picking when first met in visit sequence. // But here, we will pick whenever we reach it unless it is the first encounter and we are at the initial visit pass // How to tell "first encounter"? We'll only mark defer as NOT pick on the first time we encounter idx // anywhere. We need a flag to say whether we've "skipped" it already. // We will use picked[idx]==0 to indicate not picked; we also need a deferredSkipped flag stored externally. // We'll rely on external logic: when we first encountered idx in visit loop we may have intentionally skipped it. // However here in process_move_to we may be passing through indices that were skipped earlier; so we'll pick them now. // Simpler: maintain an external vector<int> should_defer(M) initially only defer_idx==1, and also an external vector<int> skipped_once(M). // But since lambda can't access easily, we'll implement process inline in main simulate loop below. from = to; } // final segment to target ll dist = target - from; time += dist * ( (ll)carrying + 1 ); curPos = target; } else { // moving left: curPos > target vector<int> mids; for (int i = 0; i < M; ++i){ if (!picked[i] && pos[i] < curPos && pos[i] >= target) mids.push_back(i); } sort(mids.begin(), mids.end(), [&](int a, int b){ return pos[a] > pos[b]; }); // descending ll from = curPos; for (int idx : mids){ ll to = pos[idx]; ll dist = from - to; time += dist * ( (ll)carrying + 1 ); from = to; } ll dist = from - target; time += dist * ( (ll)carrying + 1 ); curPos = target; } }; // The above helper was intended to be generic, but we need finer control to pick when passing. // For clarity and correctness, we'll implement the main loop explicitly below, handling deferred logic. // Reset state and implement explicit simulation: time = 0; curPos = S; carrying = 0; fill(picked.begin(), picked.end(), 0); vector<int> skipped_once(M, 0); // 1 if we've encountered defer_idx and skipped it already // Now iterate through visit list, but between each consecutive stop we also allow picking deferred pos when we pass them. auto move_and_handle_between = [&](long long dest){ if (curPos == dest) return; if (curPos < dest){ // moving right: we'll consider positions in increasing order between (curPos, dest] // collect indices in increasing pos vector<pair<long long,int>> mids; for (int i = 0; i < M; ++i){ if (!picked[i] && pos[i] > curPos && pos[i] <= dest) mids.emplace_back(pos[i], i); } sort(mids.begin(), mids.end()); ll prev = curPos; for (auto &pr : mids){ ll p = pr.first; int idx = pr.second; ll d = p - prev; time += d * ( (ll)carrying + 1 ); // decide to pick now? if (idx == defer_idx && !skipped_once[idx]){ // this is the first encounter and we are supposed to skip on first pass skipped_once[idx] = 1; // do NOT pick now; just pass through (we are at position p) prev = p; curPos = p; continue; } else { // pick now carrying += cnts[idx]; time += cnts[idx]; // pick cost picked[idx] = 1; prev = p; curPos = p; } } // final segment to dest ll dlast = dest - prev; time += dlast * ( (ll)carrying + 1 ); curPos = dest; } else { // moving left: consider positions in decreasing order between [dest, curPos) vector<pair<long long,int>> mids; for (int i = 0; i < M; ++i){ if (!picked[i] && pos[i] < curPos && pos[i] >= dest) mids.emplace_back(pos[i], i); } sort(mids.begin(), mids.end(), greater<pair<long long,int>>()); ll prev = curPos; for (auto &pr : mids){ ll p = pr.first; int idx = pr.second; ll d = prev - p; time += d * ( (ll)carrying + 1 ); if (idx == defer_idx && !skipped_once[idx]){ skipped_once[idx] = 1; prev = p; curPos = p; continue; } else { carrying += cnts[idx]; time += cnts[idx]; picked[idx] = 1; prev = p; curPos = p; } } ll dlast = prev - dest; time += dlast * ( (ll)carrying + 1 ); curPos = dest; } }; // Now simulate visiting sequence for (int id : visit){ // if already picked (maybe via passing), skip if (picked[id]) continue; // move from curPos to pos[id], handling any interim deferred picks move_and_handle_between(pos[id]); // upon arrival, if this position still unpicked: if (!picked[id]){ if (id == defer_idx && !skipped_once[id]){ // skip (mark skipped) skipped_once[id] = 1; // we are at pos[id], but did not pick } else { // pick now carrying += cnts[id]; time += cnts[id]; picked[id] = 1; } } } // After visiting planned waypoints, it's possible the deferred index remains unpicked and lies between curPos and G. // Move to G, and during that movement we must pick any remaining unpicked positions we cross (including defer_idx). move_and_handle_between(G); // by construction all positions should be picked return time; }; int Q; cin >> Q; for (int qi = 0; qi < Q; ++qi){ long long S, G, Tlim; cin >> S >> G >> Tlim; // find up-to-2 indices nearest to G vector<pair<long long,int>> dist_idx; for (int i = 0; i < M; ++i) dist_idx.emplace_back( llabs(pos[i] - G), i ); sort(dist_idx.begin(), dist_idx.end()); vector<int> candidates; if (!dist_idx.empty()) { candidates.push_back(dist_idx[0].second); if ((int)dist_idx.size() >= 2 && dist_idx[1].first == dist_idx[0].first) { // if tie in distance, include second; otherwise still include second as "2 closest" candidates.push_back(dist_idx[1].second); } else if ((int)dist_idx.size() >= 2) { candidates.push_back(dist_idx[1].second); } } // ensure unique sort(candidates.begin(), candidates.end()); candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end()); // options: defer none (-1), or each candidate vector<int> defers = {-1}; for (int c : candidates) defers.push_back(c); ll best = LLONG_MAX; for (bool leftFirst : {true, false}){ for (int didx : defers){ ll t = simulate_with_defer(S, G, leftFirst, didx); best = min(best, t); } } if (best <= Tlim) cout << "Yes\n"; else cout << "No\n"; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...