易知:
如果一个格子是不可退出,那么这个格子为X,或从这个格子向左(向上)走的过程中一定会出现这种情况:
?X
X?
即路径上当前格子的左边和上边都是X。
同理,如果一个格子是可退出的,那么这个格子为空且向左和向上走的过程中不会出现上述情况。
接下来我们考虑无法判断一个格子是否为空的条件。(已知网格中所有格子是否可以退出)
假设网格为n * m的矩形,当前格子为 [x, y]。那么 [x, y] 是否为空只取决于“以[x, y]为右下角的矩形所包含的所有格子”。
我们假设无论[x, y]是否为空都可以向左或向上移动(当然前提是移动到的格子为空~)。如果[x, y]可以退出(不考虑自身),则可以判断[x, y]是否为空,反之则不能。具体如下:
- [x, y]可以退出(不考虑自身)。如果[x, y]可以退出(考虑自身),那么[x, y]为空;如果[x, y]不能退出(考虑自身),那么[x, y]为X;
- [x, y]不能退出(不考虑自身),即在“出去”的过程中会遇到文章开头处提到那种情况。那么无论[x, y]是否为空,[x, y]都不能退出(考虑自身)。
综上,已知一个网格中所以格子是否可以退出时,这个网格“可确定”(能退出每一个格子是否为空)的充要条件为网格中不存在文章开头处提到的情况。
Code
#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
using namespace std;
using PII = pair<int, int>;
const int N = 2e5 + 10;
int n, m;
int x1, x2; // x1列 ~ x2列
void solve() {
cin >> n >> m;
vector <string> s(n + 1);
vector <int> lie(m + 1, 0);
for (int i = 1; i <= n; i ++) {
cin >> s[i];
s[i].insert(s[i].begin(), '0');
if (i != 1) {
// i == 1时s[i-1][j]是无效的!!!
for (int j = 1; j <= m; j ++) {
if (s[i][j - 1] == 'X' && s[i - 1][j] == 'X') {
lie[j] = 1;
}
}
}
}
for (int j = 1; j <= m; j ++) {
lie[j] += lie[j - 1];
}
int q; cin >> q;
while (q --) {
cin >> x1 >> x2;
if (lie[x2] - lie[x1] == 0) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t; cin.get();
while (t --) solve();
return 0;
}