제출 #1360962

#제출 시각아이디문제언어결과실행 시간메모리
1360962tickcrossySoccer Stadium (IOI23_soccer)C++20
6 / 100
143 ms64268 KiB
#include <vector>
#include <algorithm>
#include <unordered_map>

using namespace std;

int biggest_stadium(int N, std::vector<std::vector<int>> F) {
    long long total_empty = 0;
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (F[i][j] == 0) total_empty++;
        }
    }
    // 特判全空或全满的情况
    if (total_empty == N * N) return N * N;
    if (total_empty == 0) return 0;

    // 预处理每一行每个位置向左和向右最近的树的位置
    vector<vector<int>> prev_tree(N, vector<int>(N, -1));
    vector<vector<int>> next_tree(N, vector<int>(N, N));

    for (int r = 0; r < N; ++r) {
        int last_tree = -1;
        for (int c = 0; c < N; ++c) {
            if (F[r][c] == 1) last_tree = c;
            prev_tree[r][c] = last_tree;
        }
        last_tree = N;
        for (int c = N - 1; c >= 0; --c) {
            if (F[r][c] == 1) last_tree = c;
            next_tree[r][c] = last_tree;
        }
    }

    vector<unordered_map<int, int>> memo_up(N);
    vector<unordered_map<int, int>> memo_down(N);

    // 向上扩展的 DFS 递归加记忆化
    auto get_up = [&](auto& self, int M, int L, int R) -> int {
        if (M < 0 || L > R) return 0;
        int state = (L << 12) | R;
        if (memo_up[M].count(state)) return memo_up[M][state];

        int p_tree = prev_tree[M][R];
        int n_tree = next_tree[M][L];
        
        // 若当前区间内没有遇到树,直接继承范围
        if (p_tree < L && n_tree > R) {
            return memo_up[M][state] = (R - L + 1) + self(self, M - 1, L, R);
        }

        // 遇到树时,尝试所有被割裂的合法连通子空隙
        int mx = 0;
        int curr_l = L;
        while (curr_l <= R) {
            int t = next_tree[M][curr_l];
            int curr_r = min(R, t - 1);
            if (curr_l <= curr_r) {
                mx = max(mx, (curr_r - curr_l + 1) + self(self, M - 1, curr_l, curr_r));
            }
            curr_l = t + 1;
        }
        return memo_up[M][state] = mx;
    };

    // 向下扩展的 DFS 递归加记忆化
    auto get_down = [&](auto& self, int M, int L, int R) -> int {
        if (M >= N || L > R) return 0;
        int state = (L << 12) | R;
        if (memo_down[M].count(state)) return memo_down[M][state];

        int p_tree = prev_tree[M][R];
        int n_tree = next_tree[M][L];
        
        if (p_tree < L && n_tree > R) {
            return memo_down[M][state] = (R - L + 1) + self(self, M + 1, L, R);
        }

        int mx = 0;
        int curr_l = L;
        while (curr_l <= R) {
            int t = next_tree[M][curr_l];
            int curr_r = min(R, t - 1);
            if (curr_l <= curr_r) {
                mx = max(mx, (curr_r - curr_l + 1) + self(self, M + 1, curr_l, curr_r));
            }
            curr_l = t + 1;
        }
        return memo_down[M][state] = mx;
    };

    int max_area = 0;

    // 枚举全部可能的“骨架极大线段核心”,分别向上和向下探寻其衍生极值
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (F[i][j] == 0 && (j == 0 || F[i][j - 1] == 1)) {
                int end_j = j;
                while (end_j + 1 < N && F[i][end_j + 1] == 0) end_j++;
                
                int L = j, R = end_j;
                int area = (R - L + 1);
                
                area += get_up(get_up, i - 1, L, R);
                area += get_down(get_down, i + 1, L, R);
                
                if (area > max_area) {
                    max_area = area;
                }
                j = end_j;
            }
        }
    }

    return max_area;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…