Hướng dẫn giải của Bedao Grand Contest 17 - Tìm Mảng


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, ta tính hiệu lớn nhất có thể giữa ~2~ số (~1~ query) bằng cách hỏi câu ~2~ trên cả tập

  • Sau đó ta chặt nhị phân để tìm ~1~ trong ~2~ vị trí tạo ra hiệu lớn nhất này (~8~ query) bằng cách hỏi trên tập ~(a_1 \ldots a_{mid})~. Gọi vị trí tìm được là ~pos~

  • Sau đó ta hỏi ~2~ câu sau với mỗi bit từ ~0~ đến ~7~ (~16~ query)

    • Hỏi trên tập ~a_{pos}~ và ~a_i~ sao cho (bit ~2^i~ của ~i~ bật)

    • Hỏi trên tập ~a_i~ sao cho (bit ~2^i~ của ~i~ bật)

~\rightarrow~ Sau khi bỏ các số thuộc tập thứ ~2~ khỏi tập thứ nhất, ta có được tập hiệu giữa ~a_{pos}~ và các số ~a_i~ sao cho (bit ~2^i~ của ~i~ bật). Gọi tập này là ~P(i)~

  • Ta nhận thấy rằng: Xét một vị trí ~i~ bất kỳ, và ~m~ là tập hợp các mask của nó. Dễ thấy ~abs(a_{pos} - a_i)~ xuất hiện trong tất cả các tập ~p(x)~ với ~x~ thuộc ~m~, và ~i~ cũng là vị trí có ít bit nhất xuất hiện trong tất cả các tập này.

  • Dựa trên nhận xét trên, ta sẽ xử lý các số theo thứ tự (số nào nhiều bit nhất thì xử lý số đấy trước). Khi đến vị trí ~i~ như trên, ta chắc chắn được rằng số nào thỏa mãn tính chất trên thì chính là số chứa ~abs(a_{pos} - a_i)~

  • Đến cuối, ta hỏi thêm ~1~ câu về ~1~ số bất kỳ để xem xem ~a_{pos}~ là số bé nhất hay lớn nhất dãy (~1~ query) và suy được ra toàn bộ dãy

Tổng: ~26~ query

#include <bits/stdc++.h>
using namespace std;

const int N = 255;

int n, l, r, a[N];
map<int, int> ind;

vector<int> ask(vector<int> pos) {
    if (pos.size() == 1) {
        cout << "1 " << pos[0] << endl;
        int ret; cin >> ret; return {ret};
    } else {
        cout << "2 " << pos.size();
        for (int v : pos) {
            cout << " " << v;
        }
        cout << endl;
        vector<int> ans(pos.size() * (pos.size() - 1) / 2);
        for (int& v : ans) {
            cin >> v;
        }
        return ans;
    }
}

vector<int> solve(vector<int> pos) {
    pos.push_back(l); vector<int> lv = ask(pos); pos.pop_back();
    pos.push_back(r); vector<int> rv = ask(pos); pos.pop_back();
    multiset<int, greater<int>> le(lv.begin(), lv.end());
    multiset<int, greater<int>> ri(rv.begin(), rv.end());
    vector<int> nv = (pos.size() > 1 ? ask(pos) : vector<int>());
    for (int v : nv) {
        le.erase(le.find(v));
        ri.erase(ri.find(v));
    }
    vector<int> ans;
    while (!le.empty()) {
        int v;
        if (*le.begin() > *ri.begin()) {
            v = a[l] + *le.begin();
        } else {
            v = a[r] - *ri.begin();
        }
        ans.push_back(v);
        le.erase(le.find(abs(a[l] - v)));
        ri.erase(ri.find(abs(a[r] - v)));
    }
    return ans;
}

int main() {
    cin >> n;
    if (n == 1) {
        a[1] = ask({1})[0];
    } else {
        a[n - 1] = ask({n - 1})[0];
        a[n] = ask({n})[0];
        l = (a[n - 1] < a[n] ? n - 1 : n);
        r = 2 * n - 1 - l;
        for (int bit = 0; (1 << bit) <= n - 2; bit++) {
            vector<int> pos;
            for (int i = 1; i <= n - 2; i++) {
                if (i >> bit & 1) {
                    pos.push_back(i);
                }
            }
            vector<int> val = solve(pos);
            for (int v : val) {
                ind[v] += (1 << bit);
            }
        }
        for (auto [val, pos] : ind) {
            a[pos] = val;
        }
    }
    cout << "3";
    for (int i = 1; i <= n; i++) {
        cout << " " << a[i];
    }
    cout << endl;
}

Bình luận

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



  • -1
    dangthisac30121983  đã bình luận lúc 20, Tháng 3, 2025, 9:04

    include <bits/stdc++.h>

    using namespace std; const int N = 255; int n, l, r, a[N]; map<int, int> ind; vector<int> ask(vector<int> pos) { if (pos.size() == 1) { cout << "1 " << pos[0] << endl; int ret; cin >> ret; return {ret}; } else { cout << "2 " << pos.size(); for (int v : pos) { cout << " " << v; } cout << endl; vector<int> ans(pos.size() * (pos.size() - 1) / 2); for (int& v : ans) { cin >> v; } return ans; } } vector<int> solve(vector<int> pos) { pos.pushback(l); vector<int> lv = ask(pos); pos.popback(); pos.pushback(r); vector<int> rv = ask(pos); pos.popback(); multiset<int, greater<int>> le(lv.begin(), lv.end()); multiset<int, greater<int>> ri(rv.begin(), rv.end()); vector<int> nv = (pos.size() > 1 ? ask(pos) : vector<int>()); for (int v : nv) { le.erase(le.find(v)); ri.erase(ri.find(v)); } vector<int> ans; while (!le.empty()) { int v; if (*le.begin() > *ri.begin()) { v = a[l] + *le.begin(); } else { v = a[r] - *ri.begin(); } ans.pushback(v); le.erase(le.find(abs(a[l] - v))); ri.erase(ri.find(abs(a[r] - v))); } return ans; } int main() { cin >> n; if (n == 1) { a[1] = ask({1})[0]; } else { a[n - 1] = ask({n - 1})[0]; a[n] = ask({n})[0]; l = (a[n - 1] < a[n] ? n - 1 : n); r = 2 * n - 1 - l; for (int bit = 0; (1 << bit) <= n - 2; bit++) { vector<int> pos; for (int i = 1; i <= n - 2; i++) { if (i >> bit & 1) { pos.pushback(i); } } vector<int> val = solve(pos); for (int v : val) { ind[v] += (1 << bit); } } for (auto [val, pos] : ind) { a[pos] = val; } } cout << "3"; for (int i = 1; i <= n; i++) { cout <<a[i]<<" "; } cout << endl; }