Hướng dẫn giải của Bedao OI Contest 6 - Tranh giáng sinh


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.

Subtask 1: ~M, N \le 80~

Duyệt trâu, thử loại bỏ từng cặp tranh, thực hiện tổng dồn trên bảng ~N \cdot N~ với ~M - 2~ ô còn lại, kết quả là các ô có giá trị bằng ~0~, cập nhật đáp án.

Độ phức tạp ~O(M^2 \cdot N^2)~.

Subtask 2: ~M \le 2000~

  • Sử dụng tổng dồn để tính ~a[i][j]~ là số hình chữ nhật phủ ô ~i, j~.

  • Duyệt tất cả các cặp tranh hình chữ nhật

  • Với mỗi cặp hình chữ nhật ~(A, B)~

    • Ta chỉ quan tâm những ô vuông được phủ bởi 1 hoặc 2 bức tranh.

    • Kết quả là (số ô có ~a[i][j]=1~ của A) + (số ô có ~a[i][j]=1~ của B) + (số ô có ~a[i][j]=2~ của (~A \cap B~)) + (số ô có ~a[i][j] = 0~).

Độ phức tạp: ~O(M^2)~.

Subtask 3: ~M \le 20000, N \le 100~

Nhận xét: Ta nhận thấy để có kết quả tối ưu thì cần xóa ~2~ hình chữ nhật sao cho tổng số lượng ô bằng ~1~ và bằng ~2~ nằm trong phần giao của cả ~2~ hình là nhiều nhất.

  • Duyệt tất cả các ô ~a[i][j] = 2~, với mỗi ô tìm ~2~ hình chữ nhật bao phủ ô đó và cập nhật kết quả.

Độ phức tạp: ~O(N ^ 2 \cdot M)~.

Subtask 4: Ràng buộc gốc

  • Trường hợp 1: 2 hình chữ nhật không giao nhau.

    • Kết quả là 2 hình chữ nhật có số ô bằng 1 nhiều nhất.
  • Trường hợp 2: 2 hình chữ nhật giao nhau

    • Gọi ~sum[i][j]~ là tổng chỉ số các hcn phủ ô ~i, j~, ~sqr[i][j]~ là tổng bình phương chỉ số các hcn phủ ô ~i, j~.

    • Với mỗi ô ~a[i][j] = 2~ tìm 2 hình chữ nhật ~u, v~ phủ ô ~i, j~.

    • Khi đó ~sum[i][j] = u + v~ và ~sqr[i][j] = u^2 + v^2~. Từ đây có thể tìm ~u, v~ dễ dàng.

Độ phức tạp: ~O(N^2)~.

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 2e5 + 5, M = 5002;

int n, m, ps[3][M][M], cnt1[N], cnt2[M][M];

array<int, 4> rect[N];  

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

    freopen("CHRISTMAS.inp", "r", stdin);
    freopen("CHRISTMAS.out", "w", stdout);

    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cnt1[i] = 0;

        int x1, x2, y1, y2; cin >> x1 >> x2 >> y1 >> y2;
        rect[i] = {x1, y1, x2, y2};
        int v[3] = {1, i, i * i};
        for(int j = 0; j < 3; j++){
            ps[j][x1][y1] += v[j], ps[j][x2 + 1][y2 + 1] += v[j];
            ps[j][x1][y2 + 1] -= v[j], ps[j][x2 + 1][y1] -= v[j];
        }
    }

    int cnt0 = 0, mx1 = 0, mx2 = 0;
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            for(int k = 0; k < 3; k++){
                ps[k][i][j] += ps[k][i - 1][j] + ps[k][i][j - 1] - ps[k][i - 1][j - 1];
            }
            cnt2[i][j] += cnt2[i - 1][j] + cnt2[i][j - 1] - cnt2[i - 1][j - 1];
            if(ps[0][i][j] == 1) cnt1[ps[1][i][j]]++;
            else if(ps[0][i][j] == 0) cnt0++;
            else if(ps[0][i][j] == 2) cnt2[i][j]++;
        }
    }

    for(int i = 1; i <= n; i++){
        if(cnt1[i] > mx1) mx2 = mx1, mx1 = cnt1[i];
        else mx2 = max(mx2, cnt1[i]);
    }
    int ans = cnt0 + mx1 + mx2;

    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            if(ps[0][i][j] == 2){
                int x = ps[1][i][j];
                int y = ps[2][i][j];

                int a = 2;
                int b = -2 * x;
                int c = x * x - y;
                int delta = b * b - 4 * a * c;
                int u = (-b + sqrt(delta)) / (2 * a);
                int v = x - u;

                int x1 = max(rect[u][0], rect[v][0]), y1 = max(rect[u][1], rect[v][1]);
                int x2 = min(rect[u][2], rect[v][2]), y2 = min(rect[u][3], rect[v][3]);
                int ct2 = cnt2[x2][y2] - cnt2[x1 - 1][y2] - cnt2[x2][y1 - 1] + cnt2[x1 - 1][y1 - 1];
                ans = max(ans, cnt0 + cnt1[u] + cnt1[v] + ct2);
            }
        }
    }
    cout << ans << '\n';
}

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.