Hướng dẫn giải của Bedao OI Contest 3 - Vụ trộm thế kỷ


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Đầu tiên chúng ta có thể mô phỏng đường đi laser vào mê cung. Việc này có thể làm trong ~O(Nlog(N))~ (với ~N~ là tổng số gương trong mê cung) bằng cách lưu những vị trí gương trên các hàng và cột. Việc này có thể biểu diễn bằng các đoạn thẳng dọc và ngang.

Nếu laser đi ra khỏi mê cung, in ra ~0~. Ngược lại, ta mô phỏng ~1~ laser đi ngược từ điểm cuối của bảng tương tự như trên. Nhận xét: những điểm đặt gương hợp lệ là giao của 2 tia laser. Sử dụng sweepline để đếm và tìm điểm giao có thứ tự từ điển nhỏ nhất(sử dụng data structure như segment tree hoặc fenwick tree để đếm). Nếu số điểm giao bằng ~0~ thì in ra ~impossible~. Tổng độ phức tạp: ~O(Nlog(N))~

/*************************************
*    author: marvinthang             *
*    created: 17.07.2023 11:03:12    *
*************************************/

#include <bits/stdc++.h>

using namespace std;

#define                  fi  first
#define                  se  second
#define                left  ___left
#define               right  ___right
#define                TIME  (1.0 * clock() / CLOCKS_PER_SEC)
#define             MASK(i)  (1LL << (i))
#define           BIT(x, i)  ((x) >> (i) & 1)
#define  __builtin_popcount  __builtin_popcountll
#define              ALL(v)  (v).begin(), (v).end()
#define           REP(i, n)  for (int i = 0, _n = (n); i < _n; ++i)
#define          REPD(i, n)  for (int i = (n); i--; )
#define        FOR(i, a, b)  for (int i = (a), _b = (b); i < _b; ++i)
#define       FORD(i, b, a)  for (int i = (b), _a = (a); --i >= _a; )
#define       FORE(i, a, b)  for (int i = (a), _b = (b); i <= _b; ++i)
#define      FORDE(i, b, a)  for (int i = (b), _a = (a); i >= _a; --i)
#define        scan_op(...)  istream & operator >> (istream &in, __VA_ARGS__ &u)
#define       print_op(...)  ostream & operator << (ostream &out, const __VA_ARGS__ &u)
#ifdef LOCAL
    #include "debug.h"
#else
    #define file(name) if (fopen(name".inp", "r")) { freopen(name".inp", "r", stdin); freopen(name".out", "w", stdout); }
    #define DB(...) 23
    #define db(...) 23
    #define debug(...) 23
#endif

template <class U, class V> scan_op(pair <U, V>)  { return in >> u.first >> u.second; }
template <class T> scan_op(vector <T>)  { for (size_t i = 0; i < u.size(); ++i) in >> u[i]; return in; }
template <class U, class V> print_op(pair <U, V>)  { return out << '(' << u.first << ", " << u.second << ')'; }
template <size_t i, class T> ostream & print_tuple_utils(ostream &out, const T &tup) { if constexpr(i == tuple_size<T>::value) return out << ")";  else return print_tuple_utils<i + 1, T>(out << (i ? ", " : "(") << get<i>(tup), tup); }
template <class ...U> print_op(tuple<U...>) { return print_tuple_utils<0, tuple<U...>>(out, u); }
template <class Con, class = decltype(begin(declval<Con>()))> typename enable_if <!is_same<Con, string>::value, ostream&>::type operator << (ostream &out, const Con &con) { out << '{'; for (__typeof(con.begin()) it = con.begin(); it != con.end(); ++it) out << (it == con.begin() ? "" : ", ") << *it; return out << '}'; }

// end of template

const int MAX = 1e6 + 6;

int R, C, M, N;
set <pair <int, int>> sx[MAX], sy[MAX];

void init(void) {
    cin >> R >> M >> N;
    FORE(i, 1, R) sx[i].clear();
    FORE(i, 1, C) sy[i].clear();
    REP(i, M) {
        int x, y; cin >> y >> x;
        sx[x].emplace(y, 0);
        sy[y].emplace(x, 0);
    }
    REP(i, N) {
        int x, y; cin >> y >> x;
        sx[x].emplace(y, 1);
        sy[y].emplace(x, 1);
    }
}

using t4 = tuple <int, int, int, int>;

// index from 0
template <class T = int>
    struct Fenwick {

        T *bit = nullptr;
        int n;

        Fenwick(int _n = 0) {
            resize(_n);
        }

        void reset(void) {
            fill(bit, bit + 1 + n, T(0));
        }

        void resize(int _n) {
            if (bit != nullptr) delete[] bit;
            n = _n;
            bit = new T[n + 1];
            reset();
        }

        void update(int i, T val) {
            assert(0 <= i);
            ++i;
            for (; i <= n; i += i & -i) bit[i] += val;
        }

        T get(int i) {
            if (i < 0) return T(0);
            ++i;
            i = min(i, n);
            T res(0);
            for (; i > 0; i -= i & -i)
                res += bit[i];
            return res;
        }

        int upper_bound(T val) {
            int res = 0;
            for (int i = __lg(n); i >= 0; --i) {
                if ((res | MASK(i)) <= n && val >= bit[res | MASK(i)]) {
                    res |= MASK(i);
                    val -= bit[res];
                }
            }
            return res;
        }

        int lower_bound(T val) {
            int res = 0;
            for (int i = __lg(n); i >= 0; --i) {
                if ((res | MASK(i)) <= n && val > bit[res | MASK(i)]) {
                    res |= MASK(i);
                    val -= bit[res];
                }
            }
            return res;
        }

    };


vector <t4> go(int x, int y, int dir) {
    vector <t4> lines;
    while (true) {
        if (!dir) {
            auto it = sx[x].lower_bound(make_pair(y, 2));
            if (it == sx[x].end()) {
                lines.emplace_back(x, y, C + 1, 0);
                break;
            }
            lines.emplace_back(x, y, it->fi, 0);
            y = it->fi;
            dir = it->se ? 1 : 3;
        } else if (dir == 1) {
            auto it = sy[y].lower_bound(make_pair(x, 2));
            if (it == sy[y].end()) {
                lines.emplace_back(y, x, R + 1, 1);
                break;
            }
            lines.emplace_back(y, x, it->fi, 1);
            x = it->fi;
            dir = it->se ? 0 : 2;
        } else if (dir == 2) {
            auto it = sx[x].lower_bound(make_pair(y, 0));
            if (it == sx[x].begin()) {
                lines.emplace_back(x, y, 0, 0);
                break;
            }
            --it;
            lines.emplace_back(x, y, it->fi, 0);
            y = it->fi;
            dir = it->se ? 3 : 1;
        } else {
            auto it = sy[y].lower_bound(make_pair(x, 0));
            if (it == sy[y].begin()) {
                lines.emplace_back(y, x, 0, 1);
                break;
            }
            --it;
            lines.emplace_back(y, x, it->fi, 1);
            x = it->fi;
            dir = it->se ? 2 : 0;
        }
    }
    return lines;
}

void process(void) {
    vector <t4> ls = go(0, 1, 1);
    auto [x, l, r, t] = ls.back();
    if (t == 1 && x == C && r == R + 1) return void(cout << 0);
    vector <t4> lt = go(R + 1, C, 3);
    vector <t4> events;
    for (auto &[x, l, r, t]: ls) {
        if (l > r) swap(l, r);
        ++l; --r;
        if (!t && l <= r) {
            events.emplace_back(l, 0, x, +1);
            events.emplace_back(r + 1, 0, x, -1);
        }
    }
    for (auto &[x, l, r, t]: lt) {
        if (l > r) swap(l, r);
        ++l; --r;
        if (t && l <= r) events.emplace_back(x, 1, l, r);
    }
    sort(ALL(events));
    Fenwick <int> bit(R + 1);
    long long cnt = 0;
    pair <int, int> min_pos(C + 1, R + 1);
    for (auto [x, t, l, r]: events) {
        if (!t) bit.update(l, r);
        else {
            int a = bit.get(r);
            int b = bit.get(l - 1);
            cnt += a - b;
            if (a > b) {
                int p = bit.upper_bound(b);
                min_pos = min(min_pos, make_pair(x, p));
            }
        }
    }

    events.clear();
    for (auto [x, l, r, t]: ls) if (t && l <= r) events.emplace_back(x, 1, l, r);
    for (auto [x, l, r, t]: lt) if (!t && l <= r) {
        events.emplace_back(l, 0, x, +1);
        events.emplace_back(r + 1, 0, x, -1);
    }
    sort(ALL(events));
    for (auto [x, t, l, r]: events) {
        if (!t) bit.update(l, r);
        else {
            int a = bit.get(r);
            int b = bit.get(l - 1);
            cnt += a - b;
            if (a > b) {
                int p = bit.upper_bound(b);
                min_pos = min(min_pos, make_pair(x, p));
            }
        }
    }
    if (!cnt) cout << "impossible";
    else cout << cnt << ' ' << min_pos.fi << ' ' << min_pos.se;
}

int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(nullptr); // cout.tie(nullptr);
    file("I");
    int t = 0;
    while (cin >> C) {
        init();
        process();
        cout << '\n';
    }
    cerr << "Time elapsed: " << TIME << " s.\n";
    return (0^0);
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.