题目大意:
给定一个网格,已知光线的起始位置和方向,以及障碍物的位置,光线遇到边界或障碍物都会反弹,求光线能通过几个格子。
题解:
这是一道模拟题。
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:
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 }