2024牛客暑期多校训练营1 I.Mirror Maze(题解)大模拟

题意

给一个n*m的二维char数组,由4种镜子组成,‘’, ‘/’, ‘-’, ‘|’,镜面反射规则就是根据光线的方向和镜面的角度符合直觉的反射,然后有多组询问 ,每次给定起始位置和光线方向,求该光会经过多少面不同的镜子的反射。
在这里插入图片描述
数据大小如下:
在这里插入图片描述

思路

这是一道大模拟题
通过数据(或wa几遍)可得,循环下来很容易超时,是需要进行预处理的。
所以需要有以下几个思路

  1. 方向打表
  2. int last_ans[1005][1005][4]来存储预处理的答案。
  3. 这里不要用set<array<int,3>>st来存储成环break时的数据,因为每次的count和insert都会耗时很多时间(有一发就是因为这个wa了),最好是用多维数组int f[1005][1005][4],因为能够通过下标来查询,速度快。
  4. 这里最重要的是要知道哪些是成链形,哪些是成环型,二者的思维不一样!通过别人的思路得,如果是链型的话,是一定会射出到外面的,那么我们就遍历完四周(射入)的,剩下的就都是成环的了。
  5. 链型:因为链是从射入到射出的,所以射入那端的镜子数一定更大,这个时候就可以从射出倒着来求reverse(ans.begin(),ans.end()),这里注意!在前面solve时,不能把不反射的在那时去掉,因为那些也是链中的一部分,只是镜子不算,不然可能导致,顺着镜子的那个方向被定义为环的一部分了。所以要单独设个``bool instan```的函数,到solve1这时再去除!(这里找了好久!!!!)
  6. 环的话想对简单,就环里的大家都一样
  7. 还有一点注意点,就是关于最后ans输出这,因为所在(发出点)不算,所以我们可以直接从下一个点来算,而不是在前面复杂地倒推理!!不用假设什么点在外边,即0,n+1之类的位置。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
char mp[1005][1005];
map<string, int> mp1;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};

int m1[4] = {1, 0, 2, 3};// -
int m2[4] = {0, 1, 3, 2};// |
int m3[4] = {3, 2, 1, 0};//"/"
int m4[4] = {2, 3, 0, 1};// '\'

int last_ans[1005][1005][4];//用于求最后的答案
vector<array<int,3>>ans;//这个用于只存位置,不存方向的答案
int bf[1005][1005][4];//因为成环的前提是要位置和方向都相同 ,所以要存3个数字
bool istan(int x, int y, int dir) {  // 标记某个状态是否有经过镜子的反射
	char tem = mp[x][y];
	if (tem == '/' || tem == '\\')
		return 1;
	if (tem == '-' && (dir == 0 || dir == 1))
		return 1;
	if (tem == '|' && (dir == 2 || dir == 3))
		return 1;
	return 0;
}
void solve(int x,int y,int op) { //得到换or链的数
	while (true) {
		if (x<1 || x>n || y<1 || y>m) {
			break;
		}
		if (bf[x][y][op]) {
			break;
		}
		bf[x][y][op]=1;
		ans.push_back({x,y,op});
		if (mp[x][y]=='-') {
			op = m1[op];
		} else if (mp[x][y]=='|') {
			op = m2[op];
		} else if (mp[x][y]=='/') {
			op = m3[op];
		} else {
			op = m4[op];
		}
		x += dx[op], y += dy[op];
	}
}

void solve1(int x,int y,int op) { //处理链
	ans.clear();
	solve(x,y,op);
	int num=ans.size();//!!!注意这里的size有方向,所以不能直接用num
	reverse(ans.begin(),ans.end());//链形这里就倒着来求 
	set<pair<int,int>>s;
	for(int i=0; i<num; i++) {
		int xx=ans[i][0];
		int yy=ans[i][1];
		int opp=ans[i][2];
		if (istan(xx, yy, opp))
			s.insert({xx, yy});

		last_ans[xx][yy][opp]=s.size();
	}

}

void solve2(int x,int y,int op) {//处理环
	ans.clear();
	solve(x,y,op);
	int num=ans.size();
	set<pair<int,int>>s;
	for(int i=0; i<num; i++) {
		int xx=ans[i][0];
		int yy=ans[i][1];
		int opp=ans[i][2];
		if (istan(xx, yy, opp))
			s.insert({xx, yy});
	}
	for(int i=0; i<num; i++) {
		int xx=ans[i][0];
		int yy=ans[i][1];
		int opp=ans[i][2];
		last_ans[xx][yy][opp]=s.size();
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for(int j=1; j <= m; j++)
			cin >> mp[i][j];
	}
	mp1["above"] = 0;
	mp1["below"] = 1;
	mp1["left"] = 2;
	mp1["right"] = 3;

	for(int i=1; i<=n; i++) {
		solve1(i,1,3);
		solve1(i,m,2);
	}

	for(int j=1; j<=m; j++) {
		solve1(1,j,1);
		solve1(n,j,0);

	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			for(int k=0; k<4; k++) {
				if(!bf[i][j][k]) {
					solve2(i,j,k);
				}

			}
		}
	}


	int q;
	cin >> q;
	while (q--) {
		int x, y,op;
		string t;
		cin >> x >> y >> t;
		op=mp1[t];
		x += dx[op];
		y += dy[op];
		cout<<last_ans[x][y][op]<<"\n";
	}
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值