제출 #626149

#제출 시각아이디문제언어결과실행 시간메모리
626149I_love_Hoang_YenCatfish Farm (IOI22_fish)C++17
100 / 100
831 ms360284 KiB
#include "bits/stdc++.h"
using namespace std;

#define int long long
#define i_1 jakcjacjl
struct Fish {
    int col, row;
    int weight;
};
bool operator < (const Fish& a, const Fish& b) {
    if (a.col != b.col) return a.col < b.col;
    return a.row < b.row;
}

void upMax(int& f, int val) {
    if (val > f) f = val;
}

// sub1 - 3 {{{
// fishes are on even columns -> build piers on odd columns
// & catch all fishes
int sub1(const std::vector<Fish>& fishes) {
    int res = 0;
    for (const auto& fish : fishes) {
        res += fish.weight;
    }
    return res;
}

// fishes are on first 2 columns
int sub2(int n, const std::vector<Fish>& fishes) {
    std::vector<int> zeroes(n);  // prefix sum of fish weights at column == 0
    std::vector<int> ones(n);    // prefix sum of fish weights at column == 1
    for (const auto& fish : fishes) {
        if (fish.col == 0) zeroes[fish.row] += fish.weight;
        if (fish.col == 1) ones[fish.row] += fish.weight;
    }

    std::partial_sum(zeroes.begin(), zeroes.end(), zeroes.begin());
    std::partial_sum(ones.begin(), ones.end(), ones.begin());

    int res = ones.back();  // init: only catch fishes at column == 1
    for (int i = 0; i < n; ++i) {
        // build pier until at column 1, row 0-i
        if (n == 2) upMax(res, zeroes[i]);
        else upMax(res, zeroes[i] + ones.back() - ones[i]);
    }
    return res;
}

// all fishes are on row == 0
int sub3(int n, const std::vector<Fish>& fishes) {
    std::vector<int> weights(n);  // weights[i] = weight of fish at column i
    for (const auto& fish : fishes) {
        weights[fish.col] += fish.weight;
    }

    // f[i] = best strategy if we BUILD PIER AT i, only considering col 0..i
    // i-4 i-3 i-2 i-1 i
    std::vector<int> f(n);
    f[0] = 0;
    for (int i = 1; i < n; ++i) {
        f[i] = std::max(f[i-1], weights[i-1]);
        if (i >= 2) {
            upMax(f[i], f[i-2] + weights[i-1]);
        }
        if (i >= 3) {
            upMax(f[i], f[i-3] + weights[i-2] + weights[i-1]);
        }
    }

    int res = 0;
    for (int i = 0; i < n; ++i) {
        int cur = f[i];
        if (i + 1 < n) cur += weights[i+1];
        upMax(res, cur);
    }
    return res;
}
// }}}

// sub 5 N <= 300 {{{
int sub5(int n, const std::vector<Fish>& fishes) {
    // Init weights[i][j] = sum of fish on column i, from row 0 -> row j
    std::vector<std::vector<int>> weights(n, std::vector<int> (n, 0));
    for (const auto& fish : fishes) {
        weights[fish.col][fish.row] += fish.weight;
    }
    for (int col = 0; col < n; ++col) {
        std::partial_sum(weights[col].begin(), weights[col].end(), weights[col].begin());
    }

    // f[c][r] = best strategy if we last BUILD PIER AT column c, row r
    //           only considering fishes <= (c, r)
    // g[c][r] = similar to f[c][r] but consider fishes at column c, in row [r, n-1]
    std::vector<std::vector<int>> f(n, std::vector<int> (n, 0)),
                                  g(n, std::vector<int> (n, 0));
    // f <= g
    for (int c = 1; c < n; ++c) {
        for (int r = 0; r < n; ++r) {
            // this is first pier
            f[c][r] = g[c][r] = weights[c-1][r];

            // last pier at column i-1
            for (int lastRow = 0; lastRow < n; ++lastRow) {
                if (lastRow <= r) {
                    int cur = std::max(
                            f[c-1][lastRow] + weights[c-1][r] - weights[c-1][lastRow],
                            g[c-1][lastRow]);
                    upMax(f[c][r], cur);
                    upMax(g[c][r], cur);
                } else {
                    upMax(f[c][r], g[c-1][lastRow]);
                    upMax(g[c][r], g[c-1][lastRow] + weights[c][lastRow] - weights[c][r]);
                }
            }

            // last pier at column i-2
            if (c >= 2) {
                for (int lastRow = 0; lastRow < n; ++lastRow) {
                    int cur = g[c-2][lastRow] + weights[c-1][std::max(lastRow, r)];
                    upMax(f[c][r], cur);
                    upMax(g[c][r], cur);
                }
            }
            
            // last pier at column i-3
            if (c >= 3) {
                for (int lastRow = 0; lastRow < n; ++lastRow) {
                    int cur = g[c-3][lastRow] + weights[c-2][lastRow] + weights[c-1][r];
                    upMax(f[c][r], cur);
                    upMax(g[c][r], cur);
                }
            }
        }
    }

    int res = 0;
    for (int c = 0; c < n; ++c) {
        for (int r = 0; r < n; ++r) {
            assert(g[c][r] >= f[c][r]);
            int cur = g[c][r];
            if (c + 1 < n) {
                cur += weights[c+1][r];
            }
            upMax(res, cur);
        }
    }
    return res;
}
// }}}

// RMQ {{{
//
// Sparse table
// Usage:
// RMQ<int, _min> st(v);
//
// Note:
// - doesn't work for empty range
//
// Tested:
// - https://judge.yosupo.jp/problem/staticrmq
template<class T, T (*op) (T, T)> struct RMQ {
    RMQ() = default;
    RMQ(const vector<T>& v) : t{v}, n{(int) v.size()} {
        for (int k = 1; (1<<k) <= n; ++k) {
            t.emplace_back(n - (1<<k) + 1);
            for (int i = 0; i + (1<<k) <= n; ++i) {
                t[k][i] = op(t[k-1][i], t[k-1][i + (1<<(k-1))]);
            }
        }
    }

    // get range [l, r-1]
    // doesn't work for empty range
    T get(int l, int r) const {
        if (l == n) return 0;
        assert(0 <= l && l < r && r <= n);
        int k = __lg(r - l);
        return op(t[k][l], t[k][r - (1<<k)]);
    }

    T get_from(int l) const {
        return get(l, n);
    }

    T get_all() const {
        return get(0, n);
    }

private:
    vector<vector<T>> t;
    int n;
};
template<class T> T _min(T a, T b) { return b < a ? b : a; }
template<class T> T _max(T a, T b) { return a < b ? b : a; }
// }}}

// N <= 3000 {{{
int sub6(int n, const std::vector<Fish>& fishes) {
    // Init weights[i][j] = sum of fish on column i, from row 0 -> row j
    std::vector<std::vector<int>> weights(n, std::vector<int> (n, 0));
    for (const auto& fish : fishes) {
        weights[fish.col][fish.row] += fish.weight;
    }
    for (int col = 0; col < n; ++col) {
        std::partial_sum(weights[col].begin(), weights[col].end(), weights[col].begin());
    }

    // f[c][r] = best strategy if we last BUILD PIER AT column c, row r
    //           only considering fishes <= (c, r)
    // g[c][r] = similar to f[c][r] but consider fishes at column c, in row [r, n-1]
    std::vector<std::vector<int>> f(n, std::vector<int> (n, 0)),
                                  g(n, std::vector<int> (n, 0));
    std::vector<RMQ<int, _max>> rmq_g(n), rmq_g_with_next_col(n), rmq_f_with_next_col(n);

    for (int c = 0; c < n; ++c) {
        // compute {{{
        if (c > 0) {
            for (int r = 0; r < n; ++r) {
                // this is first pier
                f[c][r] = weights[c-1][r];

                // last pier at column i-3
                if (c >= 3) {
                    upMax(f[c][r], rmq_g_with_next_col[c-3].get_all() + weights[c-1][r]);
                }
                // last pier at column i-2
                if (c >= 2) {
                    upMax(f[c][r], std::max(
                            rmq_g[c-2].get_all() + weights[c-1][r],
                            rmq_g_with_next_col[c-2].get_all()));
                }
                g[c][r] = f[c][r];

                // last pier at column i-1
                if (c >= 1) {
                    // last row <= r
                    int cur = std::max(
                            rmq_g[c-1].get(0, r+1),
                            rmq_f_with_next_col[c-1].get(0, r+1) + weights[c-1][r]);
                    upMax(f[c][r], cur);
                    upMax(g[c][r], cur);

                    // last row > r
                    if (r + 1 < n) {
                        upMax(f[c][r], rmq_g[c-1].get(r+1, n));
                        upMax(g[c][r], rmq_g_with_next_col[c-1].get(r+1, n) - weights[c][r]);
                    }
                }
            }
        }
        // }}}
        
        // aggregate {{{
        rmq_g[c] = RMQ<int, _max> (g[c]);

        if (c + 1 < n) {
            std::vector<int> g_with_next_col(n), f_with_next_col(n);
            for (int r = 0; r < n; ++r) {
                g_with_next_col[r] = g[c][r] + weights[c+1][r];
                f_with_next_col[r] = f[c][r] - weights[c][r];
            }
            rmq_g_with_next_col[c] = RMQ<int, _max> (g_with_next_col);
            rmq_f_with_next_col[c] = RMQ<int, _max> (f_with_next_col);
        }
        // }}}
    }

    int res = 0;
    for (int c = 0; c < n; ++c) {
        for (int r = 0; r < n; ++r) {
            assert(g[c][r] >= f[c][r]);
            int cur = g[c][r];
            if (c + 1 < n) {
                cur += weights[c+1][r];
            }
            upMax(res, cur);
        }
    }
    return res;

}
// }}}

// AC {{{
int sub7(int n, const std::vector<Fish>& fishes) {
    std::vector<std::vector<int>> rows(n);  // rows[c] = important coordinates at col c
    std::vector<std::vector<int>> weights(n);  // prefix sum of weights
    std::vector<std::vector<std::pair<int,int>>> fishesAt(n);  // stores {row, weight}

    for (const auto& fish : fishes) {
        int c = fish.col;
        rows[c].push_back(fish.row);
        if (c > 0) rows[c-1].push_back(fish.row);
        if (c + 1 < n) rows[c+1].push_back(fish.row);
        fishesAt[c].push_back({fish.row, fish.weight});
    }

    for (int c = 0; c < n; ++c) {
        rows[c].push_back(-1);
        std::sort(rows[c].begin(), rows[c].end());
        rows[c].erase(std::unique(rows[c].begin(), rows[c].end()), rows[c].end());

        std::sort(fishesAt[c].begin(), fishesAt[c].end());

        weights[c].resize(rows[c].size());
        int fish_id = 0;
        for (int i = 0; i < (int) rows[c].size(); ++i) {
            if (i > 0) weights[c][i] = weights[c][i-1];
            while (fish_id < (int) fishesAt[c].size()
                    && fishesAt[c][fish_id].first <= rows[c][i]) {
                weights[c][i] += fishesAt[c][fish_id].second;
                ++fish_id;
            }
        }
    }

    // f[c][r] = best strategy if we last BUILD PIER AT column c, row r
    //           only considering fishes <= (c, r)
    // g[c][r] = similar to f[c][r] but consider fishes at column c, in row [r, n-1]
    std::vector<std::vector<int>> f(n), g(n);
    std::vector<RMQ<int, _max>> rmq_g(n), rmq_g_with_next_col(n), rmq_f_with_next_col(n);

    for (int c = 0; c < n; ++c) {
        int sz = static_cast<int> (rows[c].size());
        f[c] = g[c] = std::vector<int> (sz, 0);

        // compute {{{
        if (c > 0) {
            for (int i = 0; i < sz; ++i) {
                int i_1 = std::upper_bound(rows[c-1].begin(), rows[c-1].end(), rows[c][i])
                    - rows[c-1].begin() - 1;

                // this is first pier
                f[c][i] = weights[c-1][i_1];

                // last pier at column i-3
                if (c >= 3) {
                    upMax(f[c][i], rmq_g_with_next_col[c-3].get_all() + weights[c-1][i_1]);
                }

                // last pier at column i-2
                if (c >= 2) {
                    upMax(f[c][i], std::max(
                                rmq_g[c-2].get_all() + weights[c-1][i_1],
                                rmq_g_with_next_col[c-2].get_all()));
                }
                g[c][i] = f[c][i];

                // last pier at column i-1
                if (c >= 1) {
                    // last row <= r
                    int cur = std::max(
                            rmq_g[c-1].get(0, i_1+1),
                            rmq_f_with_next_col[c-1].get(0, i_1+1) + weights[c-1][i_1]);
                    upMax(f[c][i], cur);
                    upMax(g[c][i], cur);

                    // last row > r
                    upMax(f[c][i], rmq_g[c-1].get_from(i_1+1));
                    upMax(g[c][i], rmq_g_with_next_col[c-1].get_from(i_1+1) - weights[c][i]);
                }
            }
        }
        // }}}

        // aggregate {{{
        rmq_g[c] = RMQ<int, _max> (g[c]);
        if (c + 1 < n) {
            std::vector<int> g_with_next_col(sz), f_with_next_col(sz);
            for (int i = 0; i < sz; ++i) {
                int i_1 = std::upper_bound(rows[c+1].begin(), rows[c+1].end(), rows[c][i])
                    - rows[c+1].begin() - 1;
                g_with_next_col[i] = g[c][i] + weights[c+1][i_1];
                f_with_next_col[i] = f[c][i] - weights[c][i];
            }
            rmq_g_with_next_col[c] = RMQ<int, _max> (g_with_next_col);
            rmq_f_with_next_col[c] = RMQ<int, _max> (f_with_next_col);
        }

        // }}}
    }

    int res = 0;
    for (int c = 0; c < n; ++c) {
        int sz = rows[c].size();
        for (int i = 0; i < sz; ++i) {
            int cur = g[c][i];
            if (c + 1 < n) {
                int i_1 = std::upper_bound(rows[c+1].begin(), rows[c+1].end(), rows[c][i])
                    - rows[c+1].begin() - 1;
                cur += weights[c+1][i_1];
            }
            upMax(res, cur);
        }
    }
    return res;
}
// }}}

#undef int
long long max_weights(
        int n, int nFish,
        std::vector<int> xs,
        std::vector<int> ys,
        std::vector<int> ws) {
    std::vector<Fish> fishes;
    for (int i = 0; i < nFish; ++i) {
        fishes.push_back({xs[i], ys[i], ws[i]});
    }

    if (std::all_of(xs.begin(), xs.end(), [] (int x) { return x % 2 == 0; })) {
        return sub1(fishes);
    }
    if (*std::max_element(xs.begin(), xs.end()) <= 1) {
        return sub2(n, fishes);
    }
    if (*std::max_element(ys.begin(), ys.end()) == 0) {
        return sub3(n, fishes);
    }
    return sub7(n, fishes);
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...