제출 #1272011

#제출 시각아이디문제언어결과실행 시간메모리
1272011pvb.tunglamJakarta Skyscrapers (APIO15_skyscraper)C++20
0 / 100
1 ms572 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)4e18;

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

    int N, M;
    cin >> N >> M;
    vector<int> B(M), P(M);
    for(int i = 0; i < M; i++){
        cin >> B[i] >> P[i];
    }

    // Tính SQ = sqrt(N) ngưỡng
    int SQ = max(1, (int)(sqrt(N)) );

    // pos_at[x] = list các doge tại vị trí x
    vector<vector<int>> pos_at(N);
    for(int i = 0; i < M; i++){
        pos_at[B[i]].push_back(i);
    }

    // Với các P[u] nhỏ ≤ SQ: ta sẽ lưu trạng thái (position, p)
    // dis_small[position][p] = tối thiểu bước để tới position với khả năng nhảy p
    // Với P[u] > SQ: ta dùng trạng thái đặc biệt cho mỗi doge

    // dis_pos_p: dùng map hoặc vector size N * (SQ+1), large
    vector<vector<ll>> dis_small(N, vector<ll>(SQ+1, INF));
    // dis_doge for doges with P > SQ: dis_doge[i] = best cost khi gửi tin tới doge i
    vector<ll> dis_doge(M, INF);

    // priority_queue hoặc deque nếu dùng 0-1 BFS? Nhưng cost nhảy lớn → Dijkstra
    using T = pair<ll, pair<int,int>>; 
    // Pair: (cost, (type, id)), type 0 = small-state (pos,p), type 1 = big-doge (doge index)
    // Với type 0: id = pos * (SQ+1) + p, nhưng chúng ta dùng struct

    struct State {
        ll cost;
        int type; // 0 = small, 1 = big doge
        int id;   // if type=0: encode pos, p; if type=1: doge index
        int p_or_unused; // chỉ dùng khi type=0, là p
    };
    struct Cmp {
        bool operator()(State const &a, State const &b) const {
            return a.cost > b.cost;
        }
    };

    priority_queue<State, vector<State>, Cmp> pq;

    // Khởi đầu: doge 0 có P[0]
    if(P[0] <= SQ){
        if(dis_small[B[0]][P[0]] > 0){
            dis_small[B[0]][P[0]] = 0;
            pq.push({0, 0, B[0], P[0]});
        }
    } else {
        if(dis_doge[0] > 0){
            dis_doge[0] = 0;
            pq.push({0, 1, 0, 0}); // dùng p_or_unused = unused
        }
    }

    // Các boolean để mark truyền tin khi có doge tại cùng position
    vector<bool> used_pos_small(N * (SQ+1), false);
    vector<bool> used_pos_big(M, false); // để khi doge lớn được xử lý truyền tin

    while(!pq.empty()){
        State cur = pq.top(); pq.pop();
        ll d = cur.cost;
        int type = cur.type;
        if(type == 1 && cur.id == 1){
            // tới doge 1
            cout << d << "\n";
            return 0;
        }

        if(type == 0){
            int pos = cur.id;
            int p = cur.p_or_unused;
            if(d > dis_small[pos][p]) continue;

            // 1) Nhảy từ (pos, p) tới (pos ± p, p) nếu trong [0,N)
            for(int dir : {+1, -1}){
                int pos2 = pos + dir * p;
                if(pos2 >= 0 && pos2 < N){
                    ll nd = d + 1;
                    if(dis_small[pos2][p] > nd){
                        dis_small[pos2][p] = nd;
                        pq.push({nd, 0, pos2, p});
                    }
                }
            }

            // 2) Nếu có doge(s) tại position pos, truyền tin tới các doge nhỏ hoặc lớn
            // Man truyền tin = 0 cost, tới doge v tại pos
            for(int doge_v : pos_at[pos]){
                // v có P[v]
                if(P[doge_v] <= SQ){
                    // chuyển sang trạng thái small (pos, P[v])
                    if(dis_small[pos][P[doge_v]] > d){
                        dis_small[pos][P[doge_v]] = d;
                        pq.push({d, 0, pos, P[doge_v]});
                    }
                } else {
                    // truyền tin tới big doge
                    if(dis_doge[doge_v] > d){
                        dis_doge[doge_v] = d;
                        pq.push({d, 1, doge_v, 0});
                    }
                }
            }

        } else { // type == 1: state là “tin được ở doge u, với P[u] lớn”
            int u = cur.id;
            if(d > dis_doge[u]) continue;

            int step = P[u];
            int posu = B[u];

            // 1) từ doge, nhảy tới các vị trí posu ± k*step
            // enumerate cả hai hướng
            // mỗi bước mất cost = k
            // chúng ta muốn chuyển sang trạng thái small hoặc doge nếu gặp doge

            // hướng phải
            for(ll x = posu + step, k = 1; x < N; x += step, k++){
                ll nd = d + k;
                // trạng thái small (x, step) nếu step ≤ SQ; nếu step > SQ, chỉ có thể truyền tin khi gặp doge
                if(step <= SQ){
                    if(dis_small[x][step] > nd){
                        dis_small[x][step] = nd;
                        pq.push({nd, 0, (int)x, step});
                    }
                }
                // nếu có doge ở x
                for(int doge_v : pos_at[x]){
                    if(dis_doge[doge_v] > nd){
                        dis_doge[doge_v] = nd;
                        pq.push({nd, 1, doge_v, 0});
                    }
                }
            }
            // hướng trái
            for(ll x = posu - step, k = 1; x >= 0; x -= step, k++){
                ll nd = d + k;
                if(step <= SQ){
                    if(dis_small[x][step] > nd){
                        dis_small[x][step] = nd;
                        pq.push({nd, 0, (int)x, step});
                    }
                }
                for(int doge_v : pos_at[x]){
                    if(dis_doge[doge_v] > nd){
                        dis_doge[doge_v] = nd;
                        pq.push({nd, 1, doge_v, 0});
                    }
                }
            }
        }
    }

    // Nếu không tới doge 1
    cout << -1 << "\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...