进入博客阅读体验更佳:Mirror Maze (2024牛客多校1 I) | 付诺の小站 (funuo0728.github.io)
Mirror Maze
题目大意
给定一个n \times m(1 \le n,m \le 1000)大小的矩阵,每个格子上都有一面镜子,镜子共有以下4种类型:
-
"-" 反射来自上方和下方的光,来自左边和右边的光将平行穿过;
-
"|" 反射来自左边和右边的光,来自上方和下方的光将平行穿过;
-
"\setminus" 将来自上、下、左、右方向的光反射成朝向分别为右、左、下、上的光;
-
"/" 将来自上、下、左、右方向的光反射成朝向分别为左、右、上、下的光;
共有q(1 \le q \le 10^5)次询问,每次给出光源的位置和方向,问每个光源的光最终会反射多少枚不同的镜子。
解题思路
由于n \times m的大小的10^6,算上每格所包含的4种不同状态数量级依然为10^6,那么总共是4 \times 10 ^ 6个点,可以想到遍历预处理。
继续思考每个每个点之间的关系,发现每个点只能唯一地转移到下一个点,所以光的运动轨迹要么是个环,要么是一条链,环与链都是各自独立的,并且链的两端一定对应矩形的边界。换句话说,光一定是从外界进入到矩阵,再从矩阵中被反射出去,或者会一直在矩阵中循环。
厘清这一点就可以想到只需要对最外围的一圈做一次bfs或dfs遍历就可以预处理出所有的链,等询问碰到环的情况再去处理环。奈何笔者笨了点,并没有想到这样写,补题时的想法是反正每个点都要被遍历,那就在询问的时候进行遍历也是一样的。结果这样写还得把当前点所处的一整条链遍历处理才行,也就是说,笔者的做法是对于处在一条链上的点,首先按照反方向找到链的起点,再反向遍历到终点才行。
那么如何统计环和链所反射的镜子个数呢,只需要用一个set去存储所遍历过的镜子即可,注意到对于斜放的镜子,两面都有可能会被光经过,所以笔者采用set避免重复计算。
剩下的就只是对于模拟光在镜子上的反射过程了,比较繁琐但思路清晰,不再赘述。
参考代码
#include <bits/stdc++.h> #define maxn 1010 // #define int long long using namespace std; const double eps = 1e-8; struct node{ int x, y, s; }; int n, m, res[maxn][maxn][5], wk[5][2] = {{0, 0}, {-1, 0}, {1, 0}, {0, -1}, {0, 1}}; bool vis[maxn][maxn][5]; char g[maxn][maxn]; int get(int x, int y, string s) { int cur = (x - 1) * m * 4 + (y - 1) * 4; if(s == "above") cur += 1; else if(s == "below") cur += 2; else if(s == "left") cur += 3; else if(s == "right") cur += 4; return cur; } int get(int x, int y, int s) { int cur = (x - 1) * m * 4 + (y - 1) * 4 + s; return cur; } node irrget(int x) { node tmp = {0, 0, 0}; tmp.s = (x - 1) % 4 + 1; tmp.y = ((x - 1) % (4 * m) + 1 + 3) / 4; tmp.x = (x + 4 * m - 1) / (4 * m); return tmp; } int getdir(int x, char s) { int res; if(x == 1) { if(s == '-') res = 2; else if(s == '|') res = 1; else if(s == '/') res = 4; else if(s == '\\') res = 3; } else if(x == 2) { if(s == '-') res = 1; else if(s == '|') res = 2; else if(s == '/') res = 3; else if(s == '\\') res = 4; } else if(x == 3) { if(s == '-') res = 3; else if(s == '|') res = 4; else if(s == '/') res = 2; else if(s == '\\') res = 1; } else if(x == 4) { if(s == '-') res = 4; else if(s == '|') res = 3; else if(s == '/') res = 1; else if(s == '\\') res = 2; } return res; } int htt(node tt) { int res; if(g[tt.x][tt.y] == '-') { if(tt.s == 1) res = -1; else if(tt.s == 2) res = -1; else if(tt.s == 3) tt.s = 4, res = get(tt.x, tt.y, tt.s); else if(tt.s == 4) tt.s = 3, res = get(tt.x, tt.y, tt.s); } else if(g[tt.x][tt.y] == '|') { if(tt.s == 1) tt.s = 2, res = get(tt.x, tt.y, tt.s); else if(tt.s == 2) tt.s = 1, res = get(tt.x, tt.y, tt.s); else if(tt.s == 3) res = -1; else if(tt.s == 4) res = -1; } else if(g[tt.x][tt.y] == '\\') { if(tt.s == 1) tt.s = 4, res = get(tt.x, tt.y, tt.s); else if(tt.s == 2) tt.s = 3, res = get(tt.x, tt.y, tt.s); else if(tt.s == 3) tt.s = 2, res = get(tt.x, tt.y, tt.s); else if(tt.s == 4) tt.s = 1, res = get(tt.x, tt.y, tt.s); } else if(g[tt.x][tt.y] == '/') { if(tt.s == 1) tt.s = 3, res = get(tt.x, tt.y, tt.s); else if(tt.s == 2) tt.s = 4, res = get(tt.x, tt.y, tt.s); else if(tt.s == 3) tt.s = 1, res = get(tt.x, tt.y, tt.s); else if(tt.s == 4) tt.s = 2, res = get(tt.x, tt.y, tt.s); } return res; } int bfs(int x) { if(x == 62) { int ppp = 1; } node tt = irrget(x); if(res[tt.x][tt.y][tt.s] != -1) return res[tt.x][tt.y][tt.s]; vector<int> tmp; tmp.push_back(x); queue<int> q; q.push(x); vis[tt.x][tt.y][tt.s] = true; bool flag = false; while(q.size()) { node t = irrget(q.front()); q.pop(); int tx = t.x + wk[t.s][0], ty = t.y + wk[t.s][1]; if(tx < 1 || tx > n || ty < 1 || ty > m) continue; int ts = getdir(t.s, g[tx][ty]); if(vis[tx][ty][ts]) { int xq = get(tx, ty, ts); tmp.push_back(xq); flag = true; continue; } int xq = get(tx, ty, ts); tmp.push_back(xq); q.push(xq); vis[tx][ty][ts] = true; } if(flag) { set<pair<int, int>> cnt; int k = tmp.size(), lst = -1; for (int i = k - 1; i >= 0; --i) { node t = irrget(tmp[i]), lt; // cout << t.x << ' ' << t.y << ' ' << t.s << '\n'; if(i != k - 1) lt = irrget(tmp[i + 1]); if(lst == -1) lst = t.s; else if(t.s != lst) { lst = t.s; cnt.insert(make_pair(lt.x, lt.y)); } } for (auto u : tmp) { node t = irrget(u); res[t.x][t.y][t.s] = (int)cnt.size(); } } else { for (auto u : tmp) { node xq = irrget(u); vis[xq.x][xq.y][xq.s] = false; } tmp.clear(); int y = htt(tt); int start; if(y != -1) { q.push(y); while(q.size()) { node t = irrget(q.front()); int tx = t.x + wk[t.s][0], ty = t.y + wk[t.s][1]; if(tx < 1 || tx > n || ty < 1 || ty > m) { start = q.front(); q.pop(); continue; } q.pop(); int ts = getdir(t.s, g[tx][ty]); int xq = get(tx, ty, ts); q.push(xq); } } if(y == -1) start = x; else start = htt(irrget(start)); q.push(start); tmp.push_back(start); while(q.size()) { node t = irrget(q.front()); q.pop(); int tx = t.x + wk[t.s][0], ty = t.y + wk[t.s][1]; if(tx < 1 || tx > n || ty < 1 || ty > m) continue; int ts = getdir(t.s, g[tx][ty]); int xq = get(tx, ty, ts); tmp.push_back(xq); q.push(xq); } set<pair<int, int>> cnt; int k = tmp.size(), lst = -1; for (int i = k - 1; i >= 0; --i) { node t = irrget(tmp[i]), lt; if(i != k - 1) lt = irrget(tmp[i + 1]); if(lst == -1) lst = t.s; else if(t.s != lst) { lst = t.s; cnt.insert(make_pair(lt.x, lt.y)); } res[t.x][t.y][t.s] = cnt.size(); } } // if(vis[4][4][2]) { // cout << "x: " << x << " tt.x: " << tt.x << " tt.y: " << tt.y << " tt.s: " << tt.s << '\n'; // exit(0); // } return res[tt.x][tt.y][tt.s]; } void solve() { cin >> n >> m; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { cin >> g[i][j]; for (int k = 1; k <= 4; ++k) res[i][j][k] = -1; } } int q; cin >> q; while(q--) { int x, y; string s; cin >> x >> y >> s; cout << bfs(get(x, y, s)) << '\n'; } } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; while (t--) { solve(); } return 0; }