3669:Meteor Shower
概要
2次元平面の原点に少女がいる。少女は第一象限を1秒に1マス動ける(4近傍のいずれか)。隕石がM(<50000)個降ってくる。隕石は(x_i, y_i) in [0..300]*[0..300]に時刻t_iに落ち、(x_i, y_i)とその4近傍の格子点にはそれ以後入ることが出来ない。少女が安全地帯(隕石の影響を受けないマス)に入るまでの最小時間を求める問題。
幅優先するだけ。ただし安全地帯は[0..302]*[0..302]の中から探さないといけないことに注意。何故か[0..301]*[0..301]でも通った。テストケースが弱かったんだと思う。計算量は、R=300としてO(R^2 + M)。
int xs[50001]; int ys[50001]; int ts[50001]; int board[310][310]; int dist[310][310]; int dx[] = {0,0,1,-1,0}; int dy[] = {1,-1,0,0,0}; int M; bool isIn(int x, int y){ return 0<=x && x<=301 && 0<=y && y<=301; } #define GET(xs,v) (xs[v.first][v.second]) int solve(){ for(int i=0; i<M; i++){ for(int k=0; k<5; k++){ int ny = ys[i] + dy[k], nx = xs[i] + dx[k]; if(isIn(nx,ny) && board[nx][ny] > ts[i]){ board[nx][ny] = ts[i]; } } } if(board[0][0] == INF) return 0; for(int i=0; i<=301; i++) for(int j=0; j<=301; j++) dist[i][j] = -1; queue<pint> Q; Q.push(make_pair(0,0)); dist[0][0] = 0; while(!Q.empty()){ pint tp = Q.front(); Q.pop(); int time = GET(dist,tp) + 1; for(int k=0; k<4; k++){ int ny = tp.second + dy[k], nx = tp.first + dx[k]; if(isIn(nx,ny) && dist[nx][ny] == -1 && time < board[nx][ny]){ if(board[nx][ny] == INF) return time; dist[nx][ny] = time; Q.push(make_pair(nx,ny)); } } } return -1; }