JZOJ4823. 【NOIP2016提高A组集训第1场10.29】小W学物理

来源:互联网 发布:外汇分析软件哪个好 编辑:程序博客网 时间:2024/04/29 23:42

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;    }}
3 0