Mirror Maze (2024牛客多校1 I)

进入博客阅读体验更佳: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值