Description
为了测试小W的物理水平,Mr.X在二维坐标系中放了N面镜子(镜子坐标绝对值不超过M),镜子均与坐标轴成45°角,所以一共有两种类型“/”和“\”。原点不会有镜子,任意一点最多只有一面镜子。
镜子两个面都能反光,而中间不透光,例如,对于一个“/”型镜子,下方向射入的光线会被反射到右方向,左方向射入的光线会被反射到上方向。
现在有一条光线从原点沿X轴正方向射出,求走过T路程后所在位置。
Input
第一行三个整数N,M,T。
第2到N+1行,每行两个整数Xi,Yi,表示镜子坐标,一个字符Si表示镜子类型
Output
一行两个整数,表示走过T路程后的坐标。
Sample Input
5 2 8
0 1 \
0 2 /
1 0 /
1 1 \
1 2 \
Sample Output
3 1
Data Constraint
对于10%的数据:N=1
对于25%的数据:T<=1000000
对于35%的数据:N<=1000
对于60%的数据:M<=1000
对于100%的数据:N<=100,000,M<=1,000,000,000,T<=10^18
分析
我们知道,如果不出现循环的情况,每一个镜子最多会经过两次,即每一个面经过一次。
因为光线沿直线传播,
所以光线从一个镜子出发,如果可以到达下一个镜子,那么下一个镜子一定是与它在同一行或者同一列,而且它们之间没有任何镜子。
只要我们知道光线从每一个镜子出发,向四个方向可以到达下一个镜子的位置,就可以模拟光线到达的镜子,从而得出答案。
如何预处理一个镜子可以到达的镜子?
我们可以对镜子的横纵坐标进行排序,
例如,第一关键字是横坐标,第二关键字是纵坐标,
那么,同一列的就会排在一起,
而在同一列里面也是有顺序的,
所以就可以快速求出一个镜子向上、向下到达的镜子。
同理,向左、向右也是一样的。
如果出现循环,则就是说光线一定再次经过原点,
这是只需要将T%一下光线走一圈的长度就可以了。
code(c++)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<cmath>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{long long x,y,z;};
int g[2][4]={{3,2,1,0},{1,0,3,2}};
int n,m,p[100003][5],i,j,fx;
long long t,sum,now;
note z[100003];
char ch;
bool cmp1(note x,note y)
{
return (x.x<y.x)||((x.x==y.x)&&(x.y<y.y));
}
bool cmp2(note x,note y)
{
return (x.y<y.y)||((x.y==y.y)&&(x.x<y.x));
}
bool cmp(note x,note y)
{
return x.z<y.z;
}
int main()
{
freopen("mir.in","r",stdin);
freopen("mir.out","w",stdout);
scanf("%d%d%lld",&n,&m,&t);
fo(i,1,n)
{
scanf("%lld%lld",&z[i].x,&z[i].y);
ch=getchar();
while((ch!='/')&&(ch!=92))ch=getchar();
if(ch=='/')p[i][4]=1;
z[i].z=i;
}
fx=1;
z[0].x=z[0].y=-123456;
sort(z+1,z+1+n,cmp2);
fo(i,1,n)
{
if((z[i].y==0)&&(j==0)&&(z[i].x>0))
{
j=z[i].z;
sum=z[i].x;
fx=g[p[j][4]][fx];
}
if(z[i].y==z[i-1].y)
{
p[z[i].z][3]=z[i-1].z;
p[z[i].z][1]=z[i+1].z;
}else
{
p[z[i-1].z][1]=p[z[i].z][3]=0;
p[z[i].z][1]=z[i+1].z;
}
}
sort(z+1,z+1+n,cmp1);
fo(i,1,n)
{
if(z[i].x==z[i-1].x)
{
p[z[i].z][2]=z[i-1].z;
p[z[i].z][0]=z[i+1].z;
}else
{
p[z[i-1].z][0]=p[z[i].z][2]=0;
p[z[i].z][0]=z[i+1].z;
}
}
if((j==0)||(t<=sum))
{
printf("%lld 0",t);
return 0;
}
sort(z+1,z+1+n,cmp);
t-=sum;
while(t>0)
{
if(fx==1)now=z[p[j][1]].x-z[j].x;
if(fx==2)now=z[j].y-z[p[j][2]].y;
if(fx==3)now=z[j].x-z[p[j][3]].x;
if(fx==0)now=z[p[j][0]].y-z[j].y;
if((t<=now)||(p[j][fx]==0))
{
if(fx==1)printf("%lld %lld",z[j].x+t,z[j].y);
if(fx==2)printf("%lld %lld",z[j].x,z[j].y-t);
if(fx==3)printf("%lld %lld",z[j].x-t,z[j].y);
if(fx==0)printf("%lld %lld",z[j].x,z[j].y+t);
t=-1;
break;
}
j=p[j][fx];
fx=g[p[j][4]][fx];
t-=now;
}
}