Editorial for Hai Mảng


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.
Subtask 1:

Ta có thể dễ dàng đưa subtask này về bài toán "tìm điểm ~x~ sao cho tổng khoảng cách của ~x~ tới các điểm ~a_1, a_2, \ldots, a_n~ là nhỏ nhất có thể". Đây là bài toán cổ điển, với đáp án là đặt ~x~ thành trung vị của mảng ~a~.

Subtask 2:

Ở subtask này, ta có thể đưa về giống subtask 1 như sau: cho tập các điểm ~b~ sao cho điểm ~a_i~ xuất hiện trong tập ~c_i~ lần, ta lại tìm điểm ~x~ sao cho tổng khoảng cách của ~x~ tới các điểm trong tập ~b~ là nhỏ nhất có thể. Ta lại quan tâm tới việc tìm trung vị của tập ~b~, điều này có thể thực hiện được bằng việc chặt nhị phân đáp án, hoặc duyệt qua các giá trị của ~a~ từ bé tới lớn và lưu lại số lần xuất hiện của các giá trị bé hơn tính tới giá trị ~a_i~ đang duyệt qua.

Subtask 3:

Dễ dàng nhận ra rằng đáp án là ~-\infty~ khi và chỉ khi ~\sum_{i=1}^n c_i < 0~.

Giả sử ta đã sắp xếp mảng ~a~ tăng dần. Nhận thấy biểu thức cần tính là một hàm tuyến tính trên từng đoạn ~(-\infty, a_1), [a_1, a_2), [a_2, a_3), \ldots, [a_n, \infty)~. Ngoài ra, ta còn có một số nhận xét sau:

  • Trên đoạn ~(-\infty, a_1)~, biểu thức có dạng ~(-\sum_{i=1}^n c_i) x + (\sum_{i=1}^n c_i a_i)~.

  • Nếu biểu thức trên đoạn ~[a_{i - 1}, a_i)~ có dạng ~mx + n~, thì qua đoạn ~[a_i, a_{i + 1})~ biểu thức sẽ biến thành ~(m + 2c_i)x + (n - 2c_ia_i)~ (vì hàm ~c_i \cdot |a_i - x|~ chuyển đổi từ ~-c_i x + c_i a_i~ thành ~c_i x - c_i a_i~).

Vì thế, ta có thể duy trì hàm tuyến tính trên từng đoạn ~[a_i, a_{i + 1})~, rồi lấy giá trị nhỏ nhất ở từng đầu mút ~a_i~. Độ phức tạp của thuật toán là ~O(n \log n)~.

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

const int64_t INF = 1E18;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int t; cin >> t;
    while (t--) {
        int n; cin >> n;
        vector<int> a(n), c(n);
        // store px + q as current function
        int64_t p = 0, q = 0;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        map<int, int64_t> pos;
        for (int i = 0; i < n; i++) {
            cin >> c[i];
            // function is -cx + ac
            p -= c[i]; q += 1LL * a[i] * c[i];
            pos[a[i]] += 2 * c[i];
        }
        int64_t ans = INF;
        if (p > 0) {
            ans = -INF;
        }
        for (auto [x, v] : pos) {
            ans = min<int64_t>(ans, 1LL * p * x + q);
            p += v; q -= 1LL * x * v;
        }
        if (p < 0) {
            ans = -INF;
        }
        if (ans == -INF) {
            cout << "-inf\n";
        } else {
            cout << ans << '\n';
        }
    }
}

Comments

Please read the guidelines before commenting.


There are no comments at the moment.