제출 #1275104

#제출 시각아이디문제언어결과실행 시간메모리
1275104lmduc270410Mecho (IOI09_mecho)C++20
50 / 100
1096 ms4496 KiB
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 805;
const int INF = 1e9;

int n, k;
string a[MAXN];
int dx[4] = {0,0,-1,1};
int dy[4] = {-1,1,0,0};

int bees_time[MAXN][MAXN];
int sx=-1, sy=-1, tx=-1, ty=-1;

// precompute bees_time BFS from all H
void compute_bees_time(){
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) bees_time[i][j] = INF;
    queue<pair<int,int>> q;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(a[i][j] == 'H'){
                bees_time[i][j] = 0;
                q.push({i,j});
            }
            if(a[i][j] == 'M'){ sx=i; sy=j; }
            if(a[i][j] == 'D'){ tx=i; ty=j; }
        }
    }
    while(!q.empty()){
        auto cur = q.front(); q.pop();
        int x = cur.first, y = cur.second;
        for(int dir=0; dir<4; ++dir){
            int nx = x + dx[dir], ny = y + dy[dir];
            if(nx<0||nx>=n||ny<0||ny>=n) continue;
            if(!(a[nx][ny] == 'G' || a[nx][ny] == 'M')) continue;
            if(bees_time[nx][ny] == INF){
                bees_time[nx][ny] = bees_time[x][y] + 1;
                q.push({nx, ny});
            }
        }
    }
    // bees_time[tx][ty] remains INF (bees don't enter D)
}

// can(t): Me waits t minutes, then simulate minute-by-minute. Within each minute we do up to k expansions using bitsets.
bool can(int t){
    if(sx == -1 || tx == -1) return false;
    if(bees_time[sx][sy] <= t) return false; // bees already at start while waiting

    // precompute masks per row:
    // passable_mid: cells Me can occupy/step into during minute (passable and not occupied by bees at start)
    // passable_end: cells safe at end of minute (passable and bees won't be there at time+1)
    static bitset<MAXN> passable_mid[MAXN], passable_end[MAXN], passable_all[MAXN];
    for(int i=0;i<n;i++){
        passable_all[i].reset();
        passable_mid[i].reset();
        passable_end[i].reset();
        for(int j=0;j<n;j++){
            bool pass = (a[i][j] == 'G' || a[i][j] == 'M' || a[i][j] == 'D');
            if(pass) passable_all[i].set(j);
            if(pass && bees_time[i][j] > t) passable_mid[i].set(j);      // bees not there at start
            if(pass && bees_time[i][j] > t + 1) passable_end[i].set(j);  // safe at end of minute
        }
    }

    // current set of positions (rows of bitsets)
    static bitset<MAXN> curr[MAXN], visited[MAXN], tmp[MAXN];
    for(int i=0;i<n;i++){ curr[i].reset(); visited[i].reset(); tmp[i].reset(); }

    curr[sx].set(sy);
    visited[sx].set(sy);
    int time = t;

    // if starting at D
    if(sx == tx && sy == ty) return true;

    while(true){
        // BFS within one minute, multi-source, limited to k steps.
        // visited_in_min stores all positions reached within <=k steps this minute.
        for(int i=0;i<n;i++) visited[i] = curr[i]; // start visited = curr

        bitset<MAXN> layer[MAXN];
        for(int i=0;i<n;i++) layer[i] = curr[i];

        // if any current position is D, success
        if(curr[tx].any() && curr[tx].test(ty)) return true;

        for(int step=0; step<k; ++step){
            bool any = false;
            // compute neighbours of layer (left/right/up/down) respecting passable_mid
            // tmp = zero
            for(int r=0;r<n;r++) tmp[r].reset();

            for(int r=0;r<n;r++){
                if(layer[r].none()) continue;
                // left/right in same row
                bitset<MAXN> lr;
                lr = (layer[r] << 1) | (layer[r] >> 1);
                lr &= passable_mid[r]; // cannot step into cells that bees occupy at start
                tmp[r] |= lr;
                // up
                if(r > 0){
                    bitset<MAXN> up = layer[r];
                    up &= passable_mid[r-1];
                    tmp[r-1] |= up;
                }
                // down
                if(r+1 < n){
                    bitset<MAXN> down = layer[r];
                    down &= passable_mid[r+1];
                    tmp[r+1] |= down;
                }
            }
            // remove already visited
            for(int r=0;r<n;r++){
                tmp[r] &= (~visited[r]);
                if(tmp[r].any()) any = true;
                visited[r] |= tmp[r];
            }
            if(!any) break;
            // check if reached D in this expansion
            if(visited[tx].test(ty)) return true;
            // prepare next layer
            for(int r=0;r<n;r++) layer[r] = tmp[r];
        }

        // after up-to-k expansions, positions reachable within ≤k steps are in 'visited'
        // we can only stand at those positions at end of minute if bees_time > time+1 (i.e., passable_end)
        bool any_next = false;
        for(int r=0;r<n;r++){
            // select safe end positions
            bitset<MAXN> safe = visited[r] & passable_end[r];
            curr[r] = safe;
            if(curr[r].any()) any_next = true;
        }
        if(!any_next) return false;
        // check if any contains D
        if(curr[tx].test(ty)) return true;
        // advance minute
        time++;
        // update passable_mid and passable_end for new time
        for(int i=0;i<n;i++){
            // recompute passable_mid: passable and bees_time > time
            // recompute passable_end: passable and bees_time > time+1
            // (we could update incrementally, but recompute is O(n^2/word) per minute; acceptable)
            passable_mid[i].reset();
            passable_end[i].reset();
            for(int j=0;j<n;j++){
                bool pass = (a[i][j] == 'G' || a[i][j] == 'M' || a[i][j] == 'D');
                if(pass && bees_time[i][j] > time) passable_mid[i].set(j);
                if(pass && bees_time[i][j] > time + 1) passable_end[i].set(j);
            }
        }
        // Also remove from curr any positions that become unsafe at start of next minute:
        for(int r=0;r<n;r++){
            curr[r] &= passable_mid[r];
        }
        // loop continues
    }

    return false;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    if(!(cin >> n >> k)) return 0;
    for(int i=0;i<n;i++) cin >> a[i];
    compute_bees_time();

    // tighten upper bound: if bees reach start at B, waiting >= B is impossible
    int upper;
    if(bees_time[sx][sy] == INF) upper = n * n;
    else upper = min(n * n, bees_time[sx][sy] - 1);
    int l = 0, r = upper, ans = -1;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(can(mid)){
            ans = mid;
            l = mid + 1;
        } else r = mid - 1;
    }
    cout << ans << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...