Hướng dẫn giải của Bedao OI Contest 1 - Dỗi nhau


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.

Tác giả: Lam_lai_cuoc_doi

Subtask 1

Với mỗi ô ~(i, j)~ là biệt thự, ta tìm tất cả các ô ~(x, y)~ là biệt thự có thể đi đến từ ô ~(i, j)~ bằng BFS.

Độ phức tạp: ~\mathcal{O}((m \cdot n) ^ 2)~

Subtask 2

Gọi:

  • ~nc[i][j]~ là ô # gần nhất trên dòng ~i~ về phía bên trái của ô ~(i, j)~.
  • ~nv[i][j]~ là ô . gần nhất trên dòng ~i~ về phía bên trái của ô ~(i, j)~.

Xét ô biệt thự ~(i, j)~, với mỗi dòng ~i' \le i~, ta cần tìm trên dòng đó có bao nhiêu ô đến được ~(i, j)~. Với dòng ~i~, các ô biệt thự từ vị trí ~(i, nc[i][j] + 1)~ đến ~(i, j)~ có thể đến được ~(i, j)~. Đối với dòng ~i - 1~, các ô biệt thự từ ~(i - 1, nc[i - 1][nc[i][j] + 1] + 1)~ đến ~(i - 1, nv[i - 1][j])~ sẽ thỏa mãn đến được ~(i, j)~, tương tự với ~i-2, i-3, \dots~

Độ phức tạp: ~\mathcal{O}(m^2 \cdot n)~

Subtask 3

Ta sẽ cải tiến từ subtask 2 bằng các sử dụng hai mảng prefix sum. Để hiểu rõ hơn các bạn có thể tham khảo code ở dưới.

Độ phức tạp: ~\mathcal{O}(m \cdot n)~

Code mẫu

#include <bits/stdc++.h>
#define int long long
#define ii pair<int, int>
#define st first
#define nd second
#define endl "\n"
#define all(v) v.begin(), v.end()
#define Unique(v) v.erase(unique(all(v)), v.end())

using namespace std;

const int maxn = 2e3 + 5;

int m, n;
char a[maxn][maxn];
int valid[maxn][maxn];
int nearC[maxn][maxn];
int nearV[maxn][maxn];
int res = 0;


namespace SUB1{
    bool substask_valid(){
        return m <= 50 && n <= 50;
    }

    bool vis[405][405];
    bool valid(int i, int j){
        return i >= 1 && i <= m && j >= 1 && j <= n && a[i][j] == '.';
    }

    int BFS(int i, int j){
        queue<pair<int, int>> qu;
        memset(vis, 0, sizeof(vis));
        qu.push({i, j});
        vis[i][j] = 1;
        int cnt = 0;
        while (qu.size()){
            auto [u, v] = qu.front();
            ++cnt;
            qu.pop();

            if (valid(u + 1, v) && !vis[u + 1][v]){

                vis[u + 1][v] = 1;
                qu.push({u + 1, v});
            }
            if (valid(u, v + 1) && !vis[u][v + 1]){
                vis[u][v + 1] = 1;
                qu.push({u, v + 1});
            }
        }
        return cnt;

    }
    void solve(){

        for (int row = 1; row <= m; row++){
            for (int col = 1; col <= n; col++){
                if (a[row][col] == '#') continue;
                res -= BFS(row, col);
            }
        }
        cout << res << endl;
    }
}

namespace SUB2{
    bool subtask_valid(){
        return m <= 400 && n <= 400;
    }

    const int maxn = 405;

    void solve(){
        for (int row = 1; row <= m; row++){
            for (int col = 1; col <= n; col++){
                if (a[row][col] == '#') continue;
                int insRow = row;
                int l = nearC[row][col] + 1, r = col;
                while (insRow && l <= r){
                    res -= (valid[insRow][r] - valid[insRow][l - 1]);
                    l = nearC[insRow - 1][l] + 1;
                    r = nearV[insRow - 1][r];
                    insRow--;
                }

            }
        }
        cout << res << endl;
    }

}

namespace SUB3{

    int le[maxn][maxn], ri[maxn][maxn];
    void solve(){
        for (int row = 1; row <= m; row++){
            for (int col = 1; col <= n; col++){
                if (a[row][col] == '#') continue;

                int l = nearC[row][col] + 1, r = col;
                le[row][l] = le[row - 1][nearC[row - 1][l] + 1] - valid[row][l - 1]; 
                ri[row][r] = ri[row - 1][nearV[row - 1][r]] + valid[row][r];

                res -= (le[row][l] + ri[row][r]);
            }
        }
        cout << res << endl;
    }
}

void PROGRAM(int _){
    cin >> m >> n;

    for (int i = 1; i <= m; i++){
        for (int j = 1; j <= n; j++){
            cin >> a[i][j];
            nearC[i][j] = nearC[i][j - 1];
            nearV[i][j] = nearV[i][j - 1];
            if (a[i][j] == '#') nearC[i][j] = j;
            if (a[i][j] == '.') nearV[i][j] = j;

            valid[i][j] = valid[i][j - 1] + (a[i][j] == '.');
            res += (a[i][j] == '.');
        }
    }

    res = res * (res + 1) / 2;    
    SUB3::solve();


}

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

    int test = 1;
    for (int _ = 1; _ <= test; _++){
        PROGRAM(_);
    }

    return 0;
}

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.