คำอธิบายวิธีทำพร้อม code สำหรับข้อ toi20_orbs

สรุปโจทย์

มีลูกแก้ว NN ลูก ลูกที่ ii หนัก wiw_i โดยเราจะทำการเลือกลูกแก้วสองลูก LL ครั้ง โดยในทุกๆครั้งจะเลือกลูกแก้วที่มีน้ำหนักเป็นอันดับที่ aa เป็นลูกแรกและเลือกลูกแก้วน้ำหนักเป็นอันดับที่ bb เป็นลูกที่สองไปใส่ในเครื่องจักร

สิ่งที่เกิดขึ้นเมื่อใส่ลูกแก้วที่มีน้ำหนักเท่ากับ p,qp,q เป็นลูกแรกกับลูกที่สองตามลำดับในเครื่องจักร:เมื่อใส่ในเครื่องจักรแล้ว เครื่องจักรจะทำลายลูกแก้วทั้งสองลูกและให้ลูกแก้วที่มีน้ำหนัก qpq-p กับลูกแก้วที่มีน้ำหนัก p+q2⌊\frac{p+q}{2}⌋ ออกมาแทน

ให้ print น้ำหนักลูกแก้วที่เรียงจากน้อยไปมาก

หมายเหตุ: x⌊x⌋ หมายถึง floor function ของ xx ซึ่งเป็นจำนวนเต็มที่มีค่ามากที่สุดที่น้อยกว่าหรือเท่ากับ xx

Prerequisites

ขอบเขตข้อมูล

วิธีทำ

สังเกตได้ว่าจะเลือกลูกแก้วที่ทีน้ำหนักเป็นอันดับที่ aa กับ bb เสมอแปลว่าเราแค่ต้องใช้ Data Structure ที่สามารถหาค่าในอันดับที่ aa และอันดับที่ bb ได้อย่างรวดเร็ว ดังนั้นเราจึงควรใช้ multiset เป็น Data Structure นั้นและทำให้มีรูปแบบเหมือนกับรูปต่อไปนี้

โดย
1.ลูกแก้วใน multiset1 ทุกลูกจะต้องน้อยกว่าลูกแก้วใน multiset2 ทุกลูก
2.ลูกแก้วใน multiset2 ทุกลูกจะต้องน้อยกว่าลูกแก้วใน multiset3 ทุกลูก

ถ้าให้ pp เป็นค่าน้ำหนักในอันดับที่ aa และ qq เป็นค่าน้ำหนักในอันดับที่ bb
จะสังเกตได้ว่า qp,p+q2qq-p,⌊\frac{p+q}{2}⌋ \leq q ดังนั้นเวลาใส่ลูกแก้วกลับเราจำเป็นต้องใส่ใน multiset1 หรือ multiset2 เท่านั้น โดยใส่ใน multiset2 ก่อนแล้วค่อยย้ายลูกแก้วมาใน multiset1 โดยให้เงื่อนไข 1 ยังเป็นจริง

Solution Code:

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

int main(){
    cin.tie(NULL)->sync_with_stdio(false);
    int n, t, l, r;
    cin >> n >> t >> l >> r;
    vector <int> v(n);
    for(int i = 0; i < n; i++) cin >> v[i];
    sort(v.begin(), v.end());
    multiset<int> a, b, o;
    for(int i = 0; i < l; i++){
        a.insert(v[i]);
    }
    for(int i = l; i < r; i++){
        b.insert(v[i]);
    }
    for(int i = r; i < n; i++){
        o.insert(v[i]);
    }

    while(t--){
        int x = *--a.end();
        int y = *--b.end();
        a.erase(--a.end());
        b.erase(--b.end());
        int new1 = y - x, new2 = (x + y) / 2;
        b.insert(new1);
        b.insert(new2);
        int firstB = *b.begin();
        b.erase(b.begin());
        a.insert(firstB);
        if (*--a.end() > *b.begin()) {
	        int temp1 = *--a.end(), temp2 = *b.begin();
	        a.erase(--a.end());
	        b.erase(b.begin());
	        a.insert(temp2);
	        b.insert(temp1);
        }
    }

    for(int i : a) cout << i << ' ';
    for(int i : b) cout << i << ' ';
    for(int i : o) cout << i << ' ';
}

Time Complexity: O(NlogN)O(N\log N)

หากมีข้อสงสัย comment ไว้ใต้ post ได้เลยนะครับ 🙇‍♂️🙇‍♂️
ศึกษาโจทย์เพิ่มเติมได้ที่ Fast X Fourier