Hướng dẫn giải của Bedao OI Contest 2 - Câu cá


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.

Nhận thấy với một cần câu ~i~, trong số các con cá mà cần có thể câu được, độ dài dây câu cần mua để câu được một số con cá chính là khoảng cách tới vị trí câu ~d_j~ của con cá câu được xa nhất. Với dây câu có độ dài ~d_j~, cách câu tối ưu nhất chính là câu mọi con cá ~k~ cần câu chịu được có ~d_k \leq d_j~

Subtask 1 : ~n, m, d_i \leq 10^3~

Ta có thể duyệt qua các cần câu, đồng thời lưu lại các con cá mà cần câu hiện tại có thể chịu được cân nặng và sắp xếp chúng theo khoảng cách tới vị trí câu tăng dần. Ta sẽ tính lợi nhuận cho từng prefix của các con cá được câu và lấy ~max~ của chúng.

Độ phức tạp : ~O(m n \log n)~

Subtask 2 : Không có điều kiện gì thêm

Ta nhận thấy với mỗi cần câu, ta duyệt lại từng con cá để lưu lại và tính kết quả trong ~O(n)~. Do đó, ta có thể tối ưu bằng cách sắp xếp các cần câu theo khối lượng chịu được tăng dần, các con cá theo trọng lượng tăng dần và chạy một con trỏ để thêm thông tin về các con cá có thể câu được khi duyệt qua các cần câu. Khi thêm một con cá ~i~ vào tập các con cá ta có thể câu được, kết quả chỉ thay đổi nếu độ dài của dây câu của chúng ta lớn hơn ~d_i~. Do đó, ta duy trì một \href{https://cp-algorithms.com/datastructures/segmenttree.html} {Segment Tree} Max và Range Update để có thể tính được đáp án một cách nhanh chóng.

Độ phức tạp : ~O(n\log^2 n)~

/*
Tag: 
*/
#include <bits/stdc++.h>
#define ll long long
#define ii pair<int, int>
#define st first
#define nd second
#define endl "\n"
#define all(v) v.begin(), v.end()
#define Unique(v) v.erase(unique(all(v)), v.end())

using namespace std;

const int maxn = 1e6 + 5;
const ll oo = 1e18;

struct F{
    int w, d, val;
    bool operator < (const F &other){
        return w < other.w;
    }
} a[maxn];

int b;
ii c[maxn];

int n, m;
vector<int> cm;

struct SegmentTree{
    vector<ll> seg, lazy;
    int n;

    SegmentTree(int _n = 0): n(_n){
        seg.resize(4 * n + 10);
        lazy.resize(4 * n + 10);
    }

    void build(int id, int l, int r){
        if (l == r){
            seg[id] = (ll)-b * cm[l - 1];
            return;
        }
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
        seg[id] = max(seg[id << 1], seg[id << 1 | 1]);
    }

    void push(int id, int l, int r){
        seg[id << 1] += lazy[id];
        lazy[id << 1] += lazy[id];
        seg[id << 1 | 1] += lazy[id];
        lazy[id << 1 | 1] += lazy[id];
        lazy[id] = 0;
    }

    void update(int id, int l, int r, int ls, int rs, ll val){
        if (ls > r || l > rs) return;
        if (ls <= l && r <= rs){
            seg[id] += val;
            lazy[id] += val;
            return;
        }
        push(id, l, r);
        int mid = (l + r) >> 1;
        update(id << 1, l, mid, ls, rs, val);
        update(id << 1 | 1, mid + 1, r, ls, rs, val);
        seg[id] = max(seg[id << 1], seg[id << 1 | 1]);
    }

    ll get(int id, int l, int r, int ls, int rs){
        if (l > rs || ls > r) return -oo;
        if (ls <= l && r <= rs) return seg[id];
        push(id, l, r);
        int mid = (l + r) >> 1;
        return max(get(id << 1, l, mid, ls, rs), get(id << 1 | 1, mid + 1, r, ls, rs));
    }

    void build(){
        build(1, 1, n);
    }

    ll get(int l, int r){
        return get(1, 1, n, l, r);
    }
    void update(int l, int r, int val){
        update(1, 1, n, l, r, val);
    }
};


void PROGRAM(int _){
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i].w >> a[i].d >> a[i].val;
        cm.push_back(a[i].d);
    }

    cin >> m;
    for (int i = 1; i <= m; i++){
        cin >> c[i].st >> c[i].nd;
    }
    cin >> b;


    sort(a + 1, a + n + 1);
    sort(all(cm));
    Unique(cm);
    int t = cm.size();

    for (int i = 1; i <= n; i++){
        a[i].d = lower_bound(all(cm), a[i].d) - cm.begin() + 1;
    }


    SegmentTree d(t);
    d.build();

    sort(c + 1, c + m + 1);
    int ins = 1;

    ll res = 0;

    for (int i = 1; i <= m; i++){
        while (ins <= n && a[ins].w <= c[i].st){
            d.update(a[ins].d, t, a[ins].val);
            ins++;
        }
        res = max(res, (ll)-c[i].nd + d.get(1, t));      
    }

    cout << res << endl;


}

signed main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    int test = 1;
    // cin >> test;

    for (int _ = 1; _ <= test; _++){
        PROGRAM(_);
    }

    return 0;
}

Bình luận

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


Không có bình luận tại thời điểm này.