题目大意:
给定一个网格,已知光线的起始位置和方向,以及障碍物的位置,光线遇到边界或障碍物都会反弹,求光线能通过几个格子。
题解:
这是一道模拟题。
60%数据(n,m<=1000)
直接n2模拟,用x,y,z记录光线的位置及方向,用二维数组记录地图状况,不断移动直至回到起点(方向与出发时一致),把路径上的点都打上标记,最后统计标记的数量即可。
复杂度O(nm)。
其实模拟有几个小技巧:
1、开始时可以将地图边缘都存成障碍物,可省去不少判断;
2、宏定义数组{1,1,-1,-1},{1,-1,1,-1}代表方向;
3、模拟时只打标记,最后统计答案。
100%数据(n,m<=100000)
n2显然受不了,我们需要想办法将程序优化到nlogn。
n,m大小的数组开不下,我们可以用STL的vector存储障碍的位置,和上面一样,地图边界也视为障碍物。假设(1,1)在左上角,则对于每条左上——右下的直线,其上的点横坐标与纵坐标的差相等,右上——左下的直线,其上的点横纵坐标之和相等,我们可以利用此性质给直线标号。每条直线所对应的vector里只用存横坐标,纵坐标可以算出。
将每个障碍物存进vector里以后,sort一下,然后我们可以利用二分求出某个方向上最近的障碍物,在vector里二分查找,复杂度为logn,可以接受。
我们在模拟时,可以将模拟加速,就是每次跳到一条直线的尽头,然后改变方向,直至回到起点。此时不能再打标记,只能将路径长度相加。值得注意的是,如果在行进过程中反向,则每个格子都会被重复经过两次,应将总答案除以2。
我们依然用三个数x,y,z表示位置及方向,每次行进时,先利用二分找到最近的障碍物,然或利用二分判断周边有没有其他可能影响路径的障碍物。二分查找相邻的直线,判断求得的位置是否与障碍物相邻即可。此时便可以用到相邻直线标号相差一的性质。
最后注意回到起点的判断,不仅要判断是否共线或同向,也要判断他们的相对位置,以及之间有没有障碍物。
复杂度O(nlogn)。
Code:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream>
2 #include<cstdio>
3 #include<string>
4 #include<cstring>
5 #include<vector>
6 #include<algorithm>
7 #define LL long long
8 using namespace std;
9 const int N=1000010;
10 int n,m,k,sx,sy,dir,d0,nowa,nowb,nxta,nxtb,flag;
11 string str;
12 vector<int> v[5][N<<1];
13 void add(int x,int y)
14 {
15 v[1][x-y+N].push_back(x);
16 v[2][x+y].push_back(x);
17 v[3][x-y+N].push_back(x);
18 v[4][x+y].push_back(x);
19 }
20 int bound(int x,int y,int z,int val)
21 {
22 int ans=-1;
23 if(z==1){
24 int l=0,r=v[x][y].size()-1;
25 while(l<=r){
26 int mid=(l+r)>>1;
27 if(v[x][y][mid]>val){
28 r=mid-1;
29 ans=mid;
30 }
31 else l=mid+1;
32 }
33 }
34 else{
35 int l=0,r=v[x][y].size()-1;
36 while(l<=r){
37 int mid=(l+r)>>1;
38 if(v[x][y][mid]<val){
39 l=mid+1;
40 ans=mid;
41 }
42 else r=mid-1;
43 }
44 }
45 return v[x][y][ans];
46 }
47 int main()
48 {
49 cin>>n>>m>>k;
50 for(int i=1;i<=k;i++){
51 int x,y;
52 scanf("%d%d",&x,&y);
53 add(x,y);
54 }
55 cin>>sx>>sy;
56 cin>>str;
57 if(str[0]=='S'){
58 if(str[1]=='E') dir=1;
59 else dir=4;
60 }
61 else{
62 if(str[1]=='E') dir=2;
63 else dir=3;
64 }
65 for(int i=0;i<=n+1;i++){
66 add(i,0);add(i,m+1);
67 }
68 for(int i=1;i<=m;i++){
69 add(0,i);add(n+1,i);
70 }
71 for(int i=0;i<=2*N-1;i++){
72 sort(v[1][i].begin(),v[1][i].end());
73 sort(v[2][i].begin(),v[2][i].end());
74 sort(v[3][i].begin(),v[3][i].end());
75 sort(v[4][i].begin(),v[4][i].end());
76 }
77 LL ans=0;int flag=0;
78 d0=dir;nowa=sx;nowb=sy;
79 while(1){
80 if(dir==1){
81 nxta=bound(1,nowa-nowb+N,1,nowa)-1;
82 nxtb=nxta-nowa+nowb;ans+=(LL)(nxta-nowa+1);
83 int a=bound(1,nowa-nowb+N+1,1,nxta),b=bound(1,nowa-nowb+N-1,1,nxta-1);
84 if(a==nxta+1&&b==nxta){
85 flag=1;dir=3;
86 nowa=nxta;nowb=nxtb;
87 }
88 else if(a==nxta+1){
89 dir=2;
90 nowa=nxta;nowb=nxtb+1;
91 }
92 else if(b==nxta){
93 dir=4;
94 nowb=nxtb;nowa=nxta+1;
95 }
96 else{
97 flag=1;dir=3;
98 nowa=nxta;nowb=nxtb;
99 }
100 }
101 else if(dir==2){
102 nxta=bound(2,nowa+nowb,2,nowa)+1;
103 nxtb=nowa+nowb-nxta;ans+=(LL)(nowa-nxta+1);
104 int a=bound(2,nowa+nowb-1,2,nxta),b=bound(2,nowa+nowb+1,2,nxta+1);
105 if(a==nxta-1&&b==nxta){
106 flag=1;dir=4;
107 nowa=nxta;nowb=nxtb;
108 }
109 else if(a==nxta-1){
110 dir=1;
111 nowa=nxta;nowb=nxtb+1;
112 }
113 else if(b==nxta){
114 dir=3;
115 nowb=nxtb;nowa=nxta-1;
116 }
117 else{
118 flag=1;dir=4;
119 nowa=nxta;nowb=nxtb;
120 }
121 }
122 else if(dir==3){
123 nxta=bound(3,nowa-nowb+N,2,nowa)+1;
124 nxtb=nxta-nowa+nowb;ans+=(LL)(nowa-nxta+1);
125 int a=bound(3,nowa-nowb+N-1,2,nxta),b=bound(3,nowa-nowb+N+1,2,nxta+1);
126 if(a==nxta-1&&b==nxta){
127 flag=1;dir=1;
128 nowa=nxta;nowb=nxtb;
129 }
130 else if(a==nxta-1){
131 dir=4;
132 nowa=nxta;nowb=nxtb-1;
133 }
134 else if(b==nxta){
135 dir=2;
136 nowb=nxtb;nowa=nxta-1;
137 }
138 else{
139 flag=1;dir=1;
140 nowa=nxta;nowb=nxtb;
141 }
142 }
143 else{
144 nxta=bound(4,nowa+nowb,1,nowa)-1;
145 nxtb=nowa+nowb-nxta;ans+=(LL)(nxta-nowa+1);
146 int a=bound(4,nowa+nowb+1,1,nxta),b=bound(4,nowa+nowb-1,1,nxta-1);
147 if(a==nxta+1&&b==nxta){
148 flag=1;dir=2;
149 nowa=nxta;nowb=nxtb;
150 }
151 else if(a==nxta+1){
152 dir=3;
153 nowa=nxta;nowb=nxtb-1;
154 }
155 else if(b==nxta){
156 dir=1;
157 nowb=nxtb;nowa=nxta+1;
158 }
159 else{
160 flag=1;dir=2;
161 nowa=nxta;nowb=nxtb;
162 }
163 }
164 if(dir==d0){
165 if(dir==1){
166 int nxt=bound(1,nowa-nowb+N,1,nowa);
167 if(nowa-nowb==sx-sy&&sx>=nowa&&sx<nxt){
168 ans+=(LL)(sx-nowa);break;
169 }
170 }
171 else if(dir==2){
172 int nxt=bound(2,nowa+nowb,2,nowa);
173 if(nowa+nowb==sx+sy&&sx<=nowa&&sx>nxt){
174 ans+=(LL)(nowa-sx);break;
175 }
176 }
177 else if(dir==3){
178 int nxt=bound(3,nowa-nowb+N,2,nowa);
179 if(nowa-nowb==sx-sy&&sx<=nowa&&sx>nxt){
180 ans+=(LL)(nowa-sx);break;
181 }
182 }
183 else{
184 int nxt=bound(4,nowa+nowb,1,nowa);
185 if(nowa+nowb==sx+sy&&sx>=nowa&&sx<nxt){
186 ans+=(LL)(sx-nowa);break;
187 }
188 }
189 }
190 }
191 if(flag==1) ans/=2;
192 cout<<ans<<endl;
193 return 0;
194 }