제출 #1269711

#제출 시각아이디문제언어결과실행 시간메모리
1269711seoul_koreaCandies (JOI18_candies)C++17
0 / 100
1 ms576 KiB
#include <iostream> // Dành cho cin, cout [4]
#include <vector>   // Dành cho std::vector, mặc dù ở đây dùng mảng tĩnh. [5]
#include <queue>    // Dành cho std::priority_queue [6]
#include <algorithm> // Dành cho std::max hoặc các hàm khác nếu cần, ceil(N/2) có thể dùng (N+1)/2 cho số nguyên dương [7]

// Định nghĩa kích thước tối đa cho N. Vì có thể tạo thêm virtual candies,
// kích thước mảng cần lớn hơn N. Tối đa N + ceil(N/2) phần tử.
// N_MAX = 200,000. => 200,000 + 100,000 = 300,000.
// Dùng 2 * N_MAX_REAL_CANDIES để an toàn.
const int N_MAX_REAL_CANDIES = 200005; // N + 5 for safety buffer
const int MAX_TOTAL_CANDIES = N_MAX_REAL_CANDIES * 2; // Đủ cho real và virtual candies

long long A[MAX_TOTAL_CANDIES]; // Mảng lưu giá trị ngon miệng của kẹo (thực và ảo) [1]
int L[MAX_TOTAL_CANDIES], R[MAX_TOTAL_CANDIES]; // Mảng danh sách liên kết đôi [CPH.pdf]
bool deleted[MAX_TOTAL_CANDIES]; // Mảng đánh dấu kẹo đã bị xóa (không hợp lệ)

// Cặp (giá_trị, chỉ_số) để lưu trong priority_queue.
// std::priority_queue mặc định là max-heap (lấy phần tử lớn nhất).
using Candy = std::pair<long long, int>;

// Mảng lưu trữ các câu trả lời cho mỗi j (số lượng kẹo được ăn)
long long answers[N_MAX_REAL_CANDIES / 2 + 5];

int main() {
    // Tối ưu hóa I/O để đọc/ghi nhanh hơn [4, 8]
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    std::cout.tie(NULL);

    int N; // Số lượng viên kẹo ban đầu [7]
    std::cin >> N;

    // Hàng đợi ưu tiên để lưu trữ các viên kẹo tiềm năng (giá trị, chỉ số)
    std::priority_queue<Candy> pq;

    // Khởi tạo các viên kẹo thực tế và danh sách liên kết đôi
    for (int i = 0; i < N; ++i) {
        std::cin >> A[i]; // Đọc giá trị ngon miệng của kẹo thứ i [1]
        L[i] = i - 1; // Chỉ số kẹo bên trái
        R[i] = i + 1; // Chỉ số kẹo bên phải
        deleted[i] = false; // Ban đầu chưa có kẹo nào bị xóa
        pq.push({A[i], i}); // Thêm kẹo vào hàng đợi ưu tiên
    }
    R[N - 1] = -1; // Viên kẹo cuối cùng không có hàng xóm bên phải

    long long current_total_sum = 0; // Tổng giá trị ngon miệng hiện tại
    int candies_eaten_count = 0;    // Số lượng kẹo đã ăn
    
    // Bộ đếm ID cho các viên kẹo ảo, bắt đầu từ N
    // Các ID này sẽ không trùng với ID của các viên kẹo thực (0 đến N-1)
    int virtual_candy_id_counter = N; 

    // Số lượng kẹo tối đa có thể ăn là ceil(N/2) [7]
    // Sử dụng phép chia số nguyên (N + 1) / 2 để tính ceil(N/2) cho số nguyên dương
    int max_candies_to_eat = (N + 1) / 2;

    // Vòng lặp chính: chọn kẹo cho đến khi đạt số lượng tối đa hoặc PQ trống
    while (candies_eaten_count < max_candies_to_eat && !pq.empty()) {
        Candy top_candy = pq.top(); // Lấy viên kẹo có giá trị cao nhất
        pq.pop(); // Xóa khỏi PQ

        long long val = top_candy.first; // Giá trị của viên kẹo
        int idx = top_candy.second;      // Chỉ số của viên kẹo

        if (deleted[idx]) { // Nếu viên kẹo này đã bị xử lý (do bị chọn hoặc bị loại bỏ bởi hàng xóm)
            continue;       // Bỏ qua và lấy viên kẹo tiếp theo
        }

        // Chọn viên kẹo này
        current_total_sum += val;
        candies_eaten_count++;
        answers[candies_eaten_count] = current_total_sum; // Lưu kết quả cho j viên kẹo

        // Đánh dấu viên kẹo hiện tại là đã bị xóa (vì đã chọn)
        deleted[idx] = true;

        // Lấy hàng xóm của viên kẹo vừa chọn
        int left_neighbor = L[idx];
        int right_neighbor = R[idx];

        // Đánh dấu các viên kẹo lân cận là đã bị xóa (vì không thể chọn chúng)
        if (left_neighbor != -1) {
            deleted[left_neighbor] = true;
        }
        if (right_neighbor != -1) {
            deleted[right_neighbor] = true;
        }

        // Tạo một viên kẹo ảo mới. Giá trị của nó là tổng của hai hàng xóm
        // trừ đi giá trị của viên kẹo hiện tại đã chọn.
        // Đây là "sự hối tiếc" nếu chúng ta đã chọn hàng xóm thay vì kẹo hiện tại.
        long long new_val = 0;
        if (left_neighbor != -1) {
            new_val += A[left_neighbor];
        }
        if (right_neighbor != -1) {
            new_val += A[right_neighbor];
        }
        new_val -= A[idx]; // Trừ đi giá trị của kẹo đã chọn để tính net change

        int new_id = virtual_candy_id_counter++; // Gán ID mới cho kẹo ảo
        A[new_id] = new_val; // Lưu giá trị của kẹo ảo

        // Cập nhật con trỏ của danh sách liên kết đôi cho viên kẹo ảo mới
        // Viên kẹo ảo sẽ nối các hàng xóm cũ của L[idx] và R[idx]
        L[new_id] = (left_neighbor != -1 ? L[left_neighbor] : -1);
        R[new_id] = (right_neighbor != -1 ? R[right_neighbor] : -1);

        // Cập nhật lại con trỏ của các hàng xóm xa hơn để chúng trỏ đến viên kẹo ảo mới
        if (L[new_id] != -1) { // Nếu có hàng xóm bên trái xa hơn
            R[L[new_id]] = new_id;
        }
        if (R[new_id] != -1) { // Nếu có hàng xóm bên phải xa hơn
            L[R[new_id]] = new_id;
        }

        // Thêm viên kẹo ảo mới vào hàng đợi ưu tiên
        pq.push({new_val, new_id});
    }

    // In ra kết quả cho mỗi j [1]
    for (int j = 1; j <= max_candies_to_eat; ++j) {
        std::cout << answers[j] << "\n";
    }

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