Submission #1078566

#TimeUsernameProblemLanguageResultExecution timeMemory
1078566PanosPask축구 경기장 (IOI23_soccer)C++17
100 / 100
1639 ms201808 KiB
#include "soccer.h"
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back

using namespace std;

typedef pair<int, int> pi;

const int INF = 1e6;

struct SegTree {
    int size;
    vector<int> tree;
    const int DEFAULT = INF;

    void init(int N) {
        size = 1;
        while (size < N) {
            size *= 2;
        }

        tree.assign(2 * size, DEFAULT);
    }

    void set(int i, int v, int x, int lx, int rx) {
        if (lx == rx - 1) {
            tree[x] = v;
            return;
        }

        int mid = (lx + rx) / 2;
        if (i < mid) {
            set(i, v, 2 * x + 1, lx, mid);
        }
        else {
            set(i, v, 2 * x + 2, mid, rx);
        }

        tree[x] = min(tree[2 * x + 1], tree[2 * x + 2]);
    }
    void set(int i, int v) {
        set(i, v, 0, 0, size);
    }

    int get(int l, int r, int x, int lx, int rx) {
        if (lx >= r || l >= rx) {
            return DEFAULT;
        }
        else if (l <= lx && rx <= r) {
            return tree[x];
        }

        int mid = (lx + rx) / 2;
        int g1 = get(l, r, 2 * x + 1, lx, mid);
        int g2 = get(l, r, 2 * x + 2, mid, rx);

        return min(g1, g2);
    }
    int get(int l, int r) {
        return get(l, r, 0, 0, size);
    }
};

int N;
vector<vector<int>> grid;
vector<SegTree> above;
vector<SegTree> below;
vector<vector<pi>> segments;

/* dp[i][j][l][r]:
 * Maximum number of added cells if we have already processed rows [i+1, j-1] and now want to use segments fully contained within [l..r)
 */
map<tuple<int, int, int ,int>, int> dp;

void swap(SegTree& a, SegTree& b)
{
    swap(a.size, b.size);
    swap(a.tree, b.tree);
}

void calculate_trees_above(vector<SegTree>& cur)
{
    vector<vector<int>> prevtrees(N, vector<int>(N));

    cur.resize(N);
    for (int r = 0; r < N; r++) {
        cur[r].init(N);
        for (int c = 0; c < N; c++) {
            if (grid[r][c]) {
                prevtrees[r][c] = 0;
            }
            else if (!r) {
                prevtrees[r][c] = 1;
            }
            else {
                prevtrees[r][c] = prevtrees[r - 1][c] + 1;
            }

            cur[r].set(c, prevtrees[r][c]);
        }
    }
}

int calculate(int i, int j, int l, int r)
{
    // Bring the dp to the optimized version
    int up = above[i].get(l, r);
    int down = below[j].get(l, r);
    i = i - up + 1;
    j = j + down - 1;

    int res = (r - l) * (up + down - 1);

    if (dp.count(make_tuple(i, j, l, r))) {
        return dp[make_tuple(i, j, l, r)] + res;
    }

    int opt = 0;

    // Move to row i - 1
    if (i > 0) {
        int last = lower_bound(segments[i - 1].begin(), segments[i - 1].end(), mp(r, -1)) - segments[i - 1].begin() - 1;
        for (int p = last; p >= 0 && segments[i - 1][p].second > l; p--) {
            opt = max(opt, calculate(i - 1, j, max(segments[i - 1][p].first, l), min(segments[i - 1][p].second, r)));
        }
    }

    // Move to row j + 1
    if (j < N - 1) {
        int last = lower_bound(segments[j + 1].begin(), segments[j + 1].end(), mp(r, -1)) - segments[j + 1].begin() - 1;
        for (int p = last; p >= 0 && segments[j + 1][p].second > l; p--) {
            opt = max(opt, calculate(i, j + 1, max(segments[j + 1][p].first, l), min(segments[j + 1][p].second, r)));
        }
    }

    dp[make_tuple(i, j, l, r)] = opt;

    return opt + res;
}

void find_segments(void)
{
    segments.resize(N);

    for (int r = 0; r < N; r++) {
        for (int c = 0; c < N; c++) {
            if (grid[r][c] == 0) {
                if (segments[r].size() == 0 || segments[r].back().second != -1) {
                    segments[r].pb(mp(c, -1));
                }
            }
            else {
                if (segments[r].size() && segments[r].back().second == -1) {
                    segments[r].back().second = c;
                }
            }
        }

        if (segments[r].size() && segments[r].back().second == -1) {
            segments[r].back().second = N;
        }
    }
}

int biggest_stadium(int n, std::vector<std::vector<int>> F)
{
    N = n;
    grid.resize(N, vector<int>(N));

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            grid[i][j] = F[i][j];
        }
    }

    find_segments();
    calculate_trees_above(above);

    reverse(grid.begin(), grid.end());
    calculate_trees_above(below);
    reverse(grid.begin(), grid.end());
    reverse(below.begin(), below.end());

    int ans = 0;
    for (int r = 0; r < N; r++) {
        for (auto s : segments[r]) {
            ans = max(ans, calculate(r, r, s.first, s.second));
        }
    }

    return ans;
}
#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...