1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
struct Prefix2D {
int h, w;
vector<int> a; // (h+1)*(w+1), 1-based prefix
void init(int H, int W) { h = H; w = W; a.assign((h + 1) * (w + 1), 0); }
inline int& at(int y, int x) { return a[y * (w + 1) + x]; }
void build(const vector<vector<int>>& base) {
for (int y = 1; y <= h; ++y) {
int row = 0;
for (int x = 1; x <= w; ++x) {
row += base[y][x];
at(y, x) = at(y - 1, x) + row;
}
}
}
inline int sum(int y1, int x1, int y2, int x2) const {
if (y1 > y2 || x1 > x2) return 0;
int W = w + 1;
auto get = [&](int y, int x) -> int { return a[y * W + x]; };
return get(y2, x2) - get(y1 - 1, x2) - get(y2, x1 - 1) + get(y1 - 1, x1 - 1);
}
};
static const int DX[4] = {1, 0, -1, 0}; // E, S, W, N
static const int DY[4] = {0, 1, 0, -1};
vector<vector<int>> buildPathVisited(const vector<string>& g, int H, int W, int dirInit, bool leftHand) {
vector<vector<int>> vis(H, vector<int>(W, 0));
auto can = [&](int ny, int nx) -> bool {
return (0 <= ny && ny < H && 0 <= nx && nx < W && g[ny][nx] == '.');
};
int x = 0, y = 0, dir = dirInit;
vis[y][x] = 1;
const long long cap = 10LL * H * W + 5;
for (long long steps = 0; !(x == W - 1 && y == H - 1) && steps < cap; ++steps) {
// turn towards the hand
dir = leftHand ? (dir + 3) & 3 : (dir + 1) & 3;
// rotate opposite way until forward is free
for (int k = 0; k < 4; ++k) {
int nx = x + DX[dir], ny = y + DY[dir];
if (can(ny, nx)) break;
dir = leftHand ? (dir + 1) & 3 : (dir + 3) & 3;
}
x += DX[dir];
y += DY[dir];
vis[y][x] = 1;
}
return vis;
}
inline bool contains(int topY, int topX, int L, int Y, int X) {
return (topY <= Y && Y <= topY + L - 1 && topX <= X && X <= topX + L - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int W, H;
if (!(cin >> W >> H)) return 0;
vector<string> g(H);
for (int i = 0; i < H; ++i) cin >> g[i];
// Canonical paths
auto visL = buildPathVisited(g, H, W, 0, true); // start facing East
auto visR = buildPathVisited(g, H, W, 1, false); // start facing South
// Prefix sums
vector<vector<int>> blk(H + 1, vector<int>(W + 1, 0));
vector<vector<int>> lp(H + 1, vector<int>(W + 1, 0));
vector<vector<int>> rp(H + 1, vector<int>(W + 1, 0));
for (int y = 1; y <= H; ++y) for (int x = 1; x <= W; ++x) {
blk[y][x] = (g[y - 1][x - 1] == '#');
lp[y][x] = visL[y - 1][x - 1];
rp[y][x] = visR[y - 1][x - 1];
}
Prefix2D psB, psL, psR; psB.init(H, W); psL.init(H, W); psR.init(H, W);
psB.build(blk); psL.build(lp); psR.build(rp);
auto fits = [&](int y, int x, int L) -> bool {
return (y + L - 1 <= H && x + L - 1 <= W);
};
auto installable = [&](int y, int x, int L) -> bool {
if (!fits(y, x, L)) return false;
if (contains(y, x, L, 1, 1)) return false;
if (contains(y, x, L, H, W)) return false;
return psB.sum(y, x, y + L - 1, x + L - 1) == 0;
};
auto blocks = [&](int y, int x, int L) -> bool {
if (!fits(y, x, L)) return false;
if (psL.sum(y, x, y + L - 1, x + L - 1) <= 0) return false;
if (psR.sum(y, x, y + L - 1, x + L - 1) <= 0) return false;
return true;
};
int bestL = INT_MAX, bestX = -1, bestY = -1;
for (int y = 1; y <= H; ++y) {
for (int x = 1; x <= W; ++x) {
if (g[y - 1][x - 1] == '#') continue; // top-left must be empty
int hiBound = min(H - y + 1, W - x + 1);
if (hiBound <= 0) continue;
// 최소로 막는 길이
int lo = 1, hi = hiBound, LminBlock = -1;
while (lo <= hi) {
int mid = (lo + hi) >> 1;
if (blocks(y, x, mid)) { LminBlock = mid; hi = mid - 1; }
else lo = mid + 1;
}
if (LminBlock < 0) continue;
// 설치 가능한 최대 길이
lo = 1; hi = hiBound; int LmaxInstall = 0;
while (lo <= hi) {
int mid = (lo + hi) >> 1;
if (installable(y, x, mid)) { LmaxInstall = mid; lo = mid + 1; }
else hi = mid - 1;
}
if (LminBlock <= LmaxInstall) {
if (LminBlock < bestL) {
bestL = LminBlock; bestX = x; bestY = y;
}
}
}
}
if (bestL == INT_MAX) cout << "Impossible\n";
else cout << bestL << ' ' << bestX << ' ' << bestY << '\n';
return 0;
}
|