题意
给一个n*m的二维char数组,由4种镜子组成,‘’, ‘/’, ‘-’, ‘|’,镜面反射规则就是根据光线的方向和镜面的角度符合直觉的反射,然后有多组询问 ,每次给定起始位置和光线方向,求该光会经过多少面不同的镜子的反射。
数据大小如下:
思路
这是一道大模拟题
通过数据(或wa几遍)可得,循环下来很容易超时,是需要进行预处理的。
所以需要有以下几个思路
- 方向打表
int last_ans[1005][1005][4]
来存储预处理的答案。- 这里不要用
set<array<int,3>>st
来存储成环break时的数据,因为每次的count和insert都会耗时很多时间(有一发就是因为这个wa了),最好是用多维数组int f[1005][1005][4]
,因为能够通过下标来查询,速度快。 - 这里最重要的是要知道哪些是成链形,哪些是成环型,二者的思维不一样!通过别人的思路得,如果是链型的话,是一定会射出到外面的,那么我们就遍历完四周(射入)的,剩下的就都是成环的了。
- 链型:因为链是从射入到射出的,所以射入那端的镜子数一定更大,这个时候就可以从射出倒着来求
reverse(ans.begin(),ans.end())
,这里注意!在前面solve时,不能把不反射的在那时去掉,因为那些也是链中的一部分,只是镜子不算,不然可能导致,顺着镜子的那个方向被定义为环的一部分了。所以要单独设个``bool instan```的函数,到solve1这时再去除!(这里找了好久!!!!) - 环的话想对简单,就环里的大家都一样
- 还有一点注意点,就是关于最后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;
}