{题解}[jzoj4823] 【NOIP2016提高A组集训第1场10.29】小W学物理

来源:互联网 发布:广州网络宽带资费标准 编辑:程序博客网 时间:2024/05/14 15:59

传送门

Description

为了测试小W的物理水平,Mr.X在二维坐标系中放了N面镜子(镜子坐标绝对值不超过M),镜子均与坐标轴成45°角,所以一共有两种类型“/”和“\”。原点不会有镜子,任意一点最多只有一面镜子。
镜子两个面都能反光,而中间不透光,例如,对于一个“/”型镜子,下方向射入的光线会被反射到右方向,左方向射入的光线会被反射到上方向。
现在有一条光线从原点沿X轴正方向射出,求走过T路程后所在位置。
对于100%的数据:N<=100,000,M<=1,000,000,000,T<=10^18

Analysis

很显然,不会出现环
如果用镜子摆成一个环,那你该如何进入呢?!
准确的说,还是会出现环的。
因为可以一开始就在环里……
也就是说,唯一的环一定会经过原点!
特判即可。
也因为没有环,
所以同一面镜子不会重复经过。
最坏情况O(2n)
注意细节。

Tips:从一面镜子走向另一面镜子时,
只需要排序,就是序列中的下一面镜子

千万不要作死二分!!!!

Code

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const long long N = 101000, M = 1001000000, T = 1000000000000000000;const long long     ctbx[4]={-1,1,0,0},    ctby[4]={0,0,1,-1},    zx[3][4]={{0,0,0,0},{3,2,1,0},{2,3,0,1}};struct node{    long long x,y,num;}a[N];bool cmp(node x,node y){return (x.x<y.x)||((x.x==y.x)&&(x.y<y.y));}bool cmp2(node x,node y){return (x.y<y.y)||((x.y==y.y)&&(x.x<y.x));}long long n,m,t;long long s,Ansx,Ansy;long long w[N][4],num[N][4];long long bz[N][4],c[N][3];int main(){    freopen("mir.in","r",stdin);freopen("mir.out","w",stdout);    long long f = 1;    scanf("%lld%lld%lld", &n, &m, &t);    for (int i = 1;i <= n;i ++)    {        char ch;        scanf("%lld %lld %c\n", &a[i].x, &a[i].y, &ch);        c[i][2] = (ch=='/')?1:2;        a[i].num = i;        c[i][0] = a[i].x, c[i][1] = a[i].y;    }    //a[i] x,y坐标 d序号(方便其他数组)     sort(a + 1, a + n + 1, cmp);    for (int i = 1;i <= n;i ++)    {        if (a[i - 1].x == a[i].x)             w[a[i].num][3] = a[i].y - a[i - 1].y,            num[a[i].num][3] = a[i - 1].num;        //a[i-1].y较小         if (a[i + 1].x == a[i].x)             w[a[i].num][2] = a[i + 1].y - a[i].y,            num[a[i].num][2] = a[i + 1].num;        //a[i+1].y较大         //num[i] 原序号为i的镜子 ([0]上[1]下[2]右[3]左)第一个镜子序号         //w[i] 原序号为i的镜子 ([0]上[1]下[2]右[3]左)第一个镜子距离     }    sort(a + 1,a + n + 1,cmp2);    for (int i = 1;i <= n;i ++)    {        if (a[i - 1].y == a[i].y)             w[a[i].num][0] = a[i].x - a[i - 1].x,            num[a[i].num][0] = a[i - 1].num;        if (a[i + 1].y == a[i].y)             w[a[i].num][1] = a[i + 1].x - a[i].x,            num[a[i].num][1] = a[i + 1].num;        //优化:先走几步...         if (a[i].y == 0 && a[i].x > 0 && s == 0)            if (a[i].y < t)                 s = a[i].num,                t -= a[i].x;            else                 Ansx = t,                Ansy = 0,                t = 0;    }    if (s == 0)         Ansx = t,        Ansy = 0,        t = 0;    for(;t;)    {        if(bz[s][f] != 0)             t = t % (bz[s][f] - t);        //bz判环         bz[s][f] = t;         f = zx[c[s][2]][f];        //zx 转向专用数组!         //f 方向         if (w[s][f] < t && num[s][f] != 0)             t -= w[s][f],            s = num[s][f];            //考虑走几步...         else             Ansx = c[s][0] + ctbx[f] * t,            Ansy = c[s][1] + ctby[f] * t,            t = 0;    }    printf("%lld %lld", Ansx, Ansy);}
0 0
原创粉丝点击