Submission #1281239

#TimeUsernameProblemLanguageResultExecution timeMemory
1281239tunademayoRoom Temperature (JOI24_ho_t1)C++20
0 / 100
0 ms568 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 positions -> pos[], cnts[]
    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 = (int)pos.size();

    // helper: index of position if exists, else -1
    auto idx_of = [&](long long v)->int{
        auto it = lower_bound(pos.begin(), pos.end(), v);
        if (it != pos.end() && *it == v) return int(it - pos.begin());
        return -1;
    };

    // simulate with choices:
    // goLeftFirst: bool
    // defer_idx: index to skip first time (-1 none)
    // pickAtStart: if true, and S coincides with a pos and it's not deferred, pick immediately before moving
    auto simulate = [&](long long S, long long G, bool goLeftFirst, int defer_idx, bool pickAtStart)-> ll {
        // build visit order: go one side fully then the other (monotone first sweep)
        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]);
        }

        ll time = 0;
        ll cur = S;
        int carrying = 0;
        vector<int> picked(M, 0);
        vector<int> skipped_once(M, 0);

        // Option: pick at start immediately if requested and there is a pos at S and it's not the deferred one
        int s_idx = idx_of(S);
        if (s_idx != -1 && pickAtStart) {
            if (defer_idx != s_idx) {
                picked[s_idx] = 1;
                carrying += cnts[s_idx];
                time += cnts[s_idx];
            } else {
                // if it's deferred and pickAtStart requested, we still skip (first time)
                skipped_once[s_idx] = 1; // mark skipped once already
            }
        }

        // helper to move from cur to dest, stopping at any unpicked positions on the way (and picking unless they are deferred on first encounter)
        auto move_and_handle = [&](ll dest){
            if (cur == dest) return;
            if (cur < dest) {
                // positions strictly between cur and dest inclusive of dest
                // collect indices with pos > cur && pos <= dest and not yet picked
                vector<pair<ll,int>> mids;
                for (int i = 0; i < M; ++i) if (!picked[i] && pos[i] > cur && pos[i] <= dest) mids.emplace_back(pos[i], i);
                sort(mids.begin(), mids.end()); // increasing
                ll prev = cur;
                for (auto &pr : mids) {
                    ll p = pr.first; int id = pr.second;
                    ll d = p - prev;
                    time += d * ( (ll)carrying + 1 );
                    prev = p;
                    cur = p;
                    if (id == defer_idx && !skipped_once[id]) {
                        // skip first time
                        skipped_once[id] = 1;
                        continue;
                    } else {
                        // pick now
                        carrying += cnts[id];
                        time += cnts[id];
                        picked[id] = 1;
                    }
                }
                // final segment to dest
                ll dlast = dest - prev;
                time += dlast * ( (ll)carrying + 1 );
                cur = dest;
            } else {
                // cur > dest: move left
                vector<pair<ll,int>> mids;
                for (int i = 0; i < M; ++i) if (!picked[i] && pos[i] < cur && pos[i] >= dest) mids.emplace_back(pos[i], i);
                sort(mids.begin(), mids.end(), greater<pair<ll,int>>()); // decreasing
                ll prev = cur;
                for (auto &pr : mids) {
                    ll p = pr.first; int id = pr.second;
                    ll d = prev - p;
                    time += d * ( (ll)carrying + 1 );
                    prev = p;
                    cur = p;
                    if (id == defer_idx && !skipped_once[id]) {
                        skipped_once[id] = 1;
                        continue;
                    } else {
                        carrying += cnts[id];
                        time += cnts[id];
                        picked[id] = 1;
                    }
                }
                ll dlast = prev - dest;
                time += dlast * ( (ll)carrying + 1 );
                cur = dest;
            }
        };

        // Walk through planned visit order; note that some positions may have been already auto-picked at start
        for (int id : visit) {
            if (picked[id]) continue;
            move_and_handle(pos[id]);
            // after arriving at pos[id], if still unpicked, decide
            if (!picked[id]) {
                if (id == defer_idx && !skipped_once[id]) {
                    skipped_once[id] = 1; // skip first time
                } else {
                    carrying += cnts[id];
                    time += cnts[id];
                    picked[id] = 1;
                }
            }
        }
        // finally move to G and pick any remaining while on the way
        move_and_handle(G);

        // Sanity: all must be picked
        // (if not, then something wrong; but we just handle remaining by extra moves if needed)
        for (int i = 0; i < M; ++i) {
            if (!picked[i]) {
                // go to it, pick, then go to G
                move_and_handle(pos[i]);
                // pick
                carrying += cnts[i];
                time += cnts[i];
                picked[i] = 1;
                move_and_handle(G);
            }
        }
        return time;
    };

    int Q; cin >> Q;
    for (int qi = 0; qi < Q; ++qi) {
        ll S, G, Tlim; cin >> S >> G >> Tlim;
        // build candidate defer indices: none (-1), nearest-to-G 1 and 2 (if exist), and S-index (if exists)
        vector<pair<ll,int>> byDist;
        for (int i = 0; i < M; ++i) byDist.emplace_back(llabs(pos[i] - G), i);
        sort(byDist.begin(), byDist.end());
        vector<int> candidates;
        candidates.push_back(-1);
        if (!byDist.empty()) candidates.push_back(byDist[0].second);
        if ((int)byDist.size() >= 2 && byDist[1].second != byDist[0].second) candidates.push_back(byDist[1].second);
        int sidx = idx_of(S);
        if (sidx != -1) candidates.push_back(sidx);
        // unique
        sort(candidates.begin(), candidates.end());
        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());

        // Also consider pickAtStart true/false (if S has pos)
        vector<bool> startChoices;
        if (sidx == -1) startChoices = {false}; else startChoices = {false, true};

        ll best = LLONG_MAX;
        for (bool leftFirst : {true, false}) {
            for (int defer_idx : candidates) {
                for (bool pickAtStart : startChoices) {
                    // make sure not to conflict: if pickAtStart==true and defer_idx==sidx -> that means picking and deferring same pos; allow it,
                    // but simulate handles skip priority (we set skipped_once for sidx if pickAtStart requested and it's deferred).
                    ll t = simulate(S, G, leftFirst, defer_idx, pickAtStart);
                    if (t < best) 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...