Submission #1186550

#TimeUsernameProblemLanguageResultExecution timeMemory
1186550sqrtxsunlightMagic Show (APIO24_show)C++17
100 / 100
4 ms632 KiB
#include "Alice.h" // Header được cung cấp
#include <vector>
#include <numeric> // Cho std::iota
#include <random>
#include <algorithm> // Cho std::shuffle, std::min/max
#include <cmath>     // Cho std::floor, std::log2
#include <vector>

namespace { // Sử dụng namespace ẩn danh để tránh xung đột tên

const int N_NODES = 5000;
const int BITS_X = 60;
const unsigned long long SEED = 123456789101112ULL; // Sử dụng hạt giống lớn

// Hàm tạo chuỗi bit PRNG 60 bit từ seed
long long generate_prng_sequence(unsigned long long seed) {
    std::mt19937_64 rng(seed);
    // Lấy 64 bit ngẫu nhiên và chỉ giữ lại 60 bit thấp
    return rng() & ((1LL << BITS_X) - 1);
}

// Hàm lấy bit thứ j (0-based) của số X
int get_bit(long long x, int j) {
    return (x >> j) & 1;
}

} // namespace ẩn danh

std::vector<std::pair<int, int>> Alice() {
    long long X = setN(N_NODES);

    long long prng_seq_val = generate_prng_sequence(SEED);
    long long x_prime_val = X ^ prng_seq_val;

    // Khởi tạo PRNG cho việc xáo trộn thứ tự
    std::mt19937_64 shuffle_rng(SEED);
    std::vector<int> indices(N_NODES - 2); // Indices from 3 to N_NODES
    std::iota(indices.begin(), indices.end(), 3);
    std::shuffle(indices.begin(), indices.end(), shuffle_rng);

    std::vector<int> p(N_NODES + 1);
    p[1] = 0; // Gốc không có cha
    p[2] = 1;

    long long stream_ptr = 0;

    // Xác định p[i] theo thứ tự đã xáo trộn
    for (int i : indices) {
        // floor(log2(0)) không xác định, i>=3 nên i-1 >= 2
        int b_i = static_cast<int>(std::floor(std::log2(static_cast<double>(i - 1))));

        if (b_i <= 0) continue; // Không cần lấy bit nếu b_i=0

        long long target_val = 0;
        for (int k = 0; k < b_i; ++k) {
            long long current_stream_pos = stream_ptr + k;
            int bit_idx_in_x_prime = current_stream_pos % BITS_X;
            int bit_val = get_bit(x_prime_val, bit_idx_in_x_prime);
            if (bit_val) {
                target_val |= (1LL << k); // Bit thứ k của target_val
            }
        }
        p[i] = static_cast<int>(target_val + 1);
        stream_ptr += b_i;
    }

    // Tạo danh sách cạnh
    std::vector<std::pair<int, int>> edges;
    edges.reserve(N_NODES - 1);
    for (int i = 2; i <= N_NODES; ++i) {
        // Đảm bảo p[i] hợp lệ (nếu i không có trong shuffled_indices và b_i > 0, cần xử lý)
        // Tuy nhiên, vòng lặp trên đã duyệt qua tất cả i từ 3 đến N_NODES.
        // Chỉ cần đảm bảo p[i] được khởi tạo hoặc tính toán.
         if (p[i] < 1 || p[i] >= i) {
             // Lỗi logic hoặc i=2. p[2] đã được đặt = 1.
             // Nếu p[i] chưa được gán (ví dụ do b_i=0), nó nên được gán giá trị mặc định?
             // Theo logic trên, chỉ p[2] có b_i=0. Mọi p[i] khác (i>=3) có b_i > 0 sẽ được gán.
             // Tuy nhiên, để an toàn, nếu p[i] không hợp lệ, gán nó về 1.
             if (i > 2 && p[i] == 0) p[i] = 1; // Gán mặc định nếu chưa được tính? (Không nên xảy ra)
         }
        edges.push_back({std::min(p[i], i), std::max(p[i], i)});
    }

    return edges;
}
#include "Bob.h" // Header được cung cấp
#include <vector>
#include <numeric> // Cho std::iota
#include <random>
#include <algorithm> // Cho std::shuffle, std::min/max
#include <cmath>     // Cho std::floor, std::log2
#include <map>
#include <vector>

namespace { // Sử dụng namespace ẩn danh

// Cần định nghĩa lại các hằng số giống Alice
const int N_NODES = 5000;
const int BITS_X = 60;
const unsigned long long SEED = 123456789101112ULL;

// Hàm tạo chuỗi bit PRNG 60 bit từ seed (phải giống hệt Alice)
long long generate_prng_sequence(unsigned long long seed) {
    std::mt19937_64 rng(seed);
    return rng() & ((1LL << BITS_X) - 1);
}

// Hàm lấy bit thứ j (0-based) của số X
int get_bit(long long x, int j) {
    return (x >> j) & 1;
}

} // namespace ẩn danh

long long Bob(std::vector<std::pair<int, int>> V) {
    long long prng_seq_val = generate_prng_sequence(SEED);

    // Khởi tạo PRNG cho việc xáo trộn thứ tự (giống hệt Alice)
    std::mt19937_64 shuffle_rng(SEED);
    std::vector<int> indices(N_NODES - 2); // Indices from 3 to N_NODES
    std::iota(indices.begin(), indices.end(), 3);
    std::shuffle(indices.begin(), indices.end(), shuffle_rng);

    std::map<int, int> known_p;
    for (const auto& edge : V) {
        int u = edge.first;
        int v = edge.second;
        int i = std::max(u, v);
        int p_val = std::min(u, v);
        // Chỉ lưu nếu p_val < i (luôn đúng với cây hợp lệ) và i > 1
        if (p_val > 0 && p_val < i) {
             known_p[i] = p_val;
        }
    }

    std::vector<int> vote0(BITS_X, 0);
    std::vector<int> vote1(BITS_X, 0);
    long long stream_ptr = 0;

    // Bỏ phiếu theo đúng thứ tự Alice đã dùng
    for (int i : indices) {
        int b_i = static_cast<int>(std::floor(std::log2(static_cast<double>(i - 1))));

         if (b_i <= 0) continue;

        // Kiểm tra xem Bob có biết p[i] không
        if (known_p.count(i)) {
            int p_val = known_p[i];
            long long target_val = p_val - 1;

            for (int k = 0; k < b_i; ++k) {
                long long current_stream_pos = stream_ptr + k;
                int bit_idx_in_x_prime = current_stream_pos % BITS_X;
                int bit_val = get_bit(target_val, k); // Lấy bit thứ k của target_val

                if (bit_val == 0) {
                    vote0[bit_idx_in_x_prime]++;
                } else {
                    vote1[bit_idx_in_x_prime]++;
                }
            }
        }
        // Dù biết hay không, stream pointer vẫn phải tăng
        stream_ptr += b_i;
    }

    // Quyết định các bit dựa trên phiếu bầu
    long long recovered_x_prime = 0;
    for (int j = 0; j < BITS_X; ++j) {
        if (vote1[j] > vote0[j]) {
            recovered_x_prime |= (1LL << j);
        }
        // Nếu vote0[j] >= vote1[j], bit là 0 (mặc định)
    }

    // Hoàn tác XOR để lấy X gốc
    long long recovered_X = recovered_x_prime ^ prng_seq_val;

    return recovered_X;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...