Submission #1360948

#TimeUsernameProblemLanguageResultExecution timeMemory
1360948tickcrossySoccer Stadium (IOI23_soccer)C++20
0 / 100
4595 ms63256 KiB
#include <vector>
#include <algorithm>
#include <iostream>

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;

    int max_area = 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;
        }
    }

    // 1. O(N^3) 枚举以每个点为顶峰核心的菱形/十字形最大的包含区域
    // 配合提前 break 剪枝,在非极端情况下退化到 O(N^2) 级别
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (F[i][j] == 1) continue;

            int area = 0;
            // 向上扩展
            int left = 0, right = N - 1;
            for (int r = i; r >= 0; --r) {
                left = max(left, prev_tree[r][j] + 1);
                right = min(right, next_tree[r][j] - 1);
                if (left > right) break;
                area += (right - left + 1);
            }
            
            // 向下扩展 (注意 i 已经在上方计算过,这里从 i+1 开始)
            left = 0, right = N - 1;
            for (int r = i + 1; r < N; ++r) {
                left = max(left, prev_tree[r][j] + 1);
                right = min(right, next_tree[r][j] - 1);
                if (left > right) break;
                area += (right - left + 1);
            }

            if (area > max_area) {
                max_area = area;
            }
        }
    }

    // 2. 利用单调栈 O(N^2) 求出最大的纯矩形作为兜底
    // 由于完全嵌套也是一种纯粹的矩形特例,这弥补了矩形偏置的极端情况
    vector<vector<int>> up(N, vector<int>(N, 0));
    for (int j = 0; j < N; ++j) {
        int cnt = 0;
        for (int i = 0; i < N; ++i) {
            if (F[i][j] == 0) cnt++;
            else cnt = 0;
            up[i][j] = cnt;
        }
    }

    for (int i = 0; i < N; ++i) {
        vector<int> left_bound(N, 0), right_bound(N, N - 1);
        vector<int> st;
        for (int j = 0; j < N; ++j) {
            while (!st.empty() && up[i][st.back()] >= up[i][j]) {
                st.pop_back();
            }
            left_bound[j] = st.empty() ? 0 : st.back() + 1;
            st.push_back(j);
        }
        st.clear();
        for (int j = N - 1; j >= 0; --j) {
            while (!st.empty() && up[i][st.back()] >= up[i][j]) {
                st.pop_back();
            }
            right_bound[j] = st.empty() ? N - 1 : st.back() - 1;
            st.push_back(j);
        }
        for (int j = 0; j < N; ++j) {
            if (up[i][j] > 0) {
                int area = up[i][j] * (right_bound[j] - left_bound[j] + 1);
                if (area > max_area) {
                    max_area = area;
                }
            }
        }
    }

    return max_area;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...