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

小W学物理

题目大意

在二维坐标系中放了 N 面镜子(镜子坐标绝对值不超过M),镜子均与坐标轴成 45 °角,镜子一共有两种类型’/’ 和’\’。原点没有镜子,任意一点最多只有一面镜子。
镜子两个面都能反光,中间不透光,例如,对于一个’/’型镜子,下方向射入的光线会被反射到右方向。
现在有一条光线从原点沿 X 轴正方向射出,求光线走过T个单位后所在位置。

数据范围

对于 100 %的数据, N <=105 M <=109 T <=1018

题解

这一题,看上去很难,实际上很简单。
首先,假设光线不会经过原点,那么每一面镜子撑死经过两次(镜子两面各一次),且不会存在环的情况,那么最多走2N次镜子后,就不会再经过镜子了。对于每一面镜子,可以通过排序预处理出它上下左右的第一面镜子即可。
倘若光线经过的原点且再次经过原点时是沿X轴的正方向射出的,则说明出现了环,这时只需令T变为(T mod 环的的长度)再重新从原点跑一遍即可。

Code(Pascal)

label 123,234;
var
    ch:char;
    n,m,t,ans,x,y:int64;
    i,j,k,l,o,p,fx,uu:longint;
    mi,fz:Array[0..100100,1..3] of int64;
procedure sjzl;
    var
        i,k:longint;
    begin
        for i:=1 to n div 2 do
        begin
            k:=n div 2+random(n div 2)+1;
            mi[0]:=mi[i];
            mi[i]:=mi[k];
            mi[k]:=mi[0];
        end;
    end;
procedure qsort(l,r:longint);
    var
        i,j,m,mm:longint;
    begin
        i:=l;
        j:=r;
        m:=mi[(l+r) div 2,1];
        mm:=mi[(l+r) div 2,2];
        repeat
            while (mi[i,1]<m) or ((mi[i,1]=m) and (mi[i,2]<mm)) do inc(i);
            while (mi[j,1]>m) or ((mi[j,1]=m) and (mi[j,2]>mm)) do dec(j);
            if i<=j then
            begin
                mi[0]:=mi[i];
                mi[i]:=mi[j];
                mi[j]:=mi[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
procedure qsortt(l,r:longint);
    var
        i,j,m,mm:longint;
    begin
        i:=l;
        j:=r;
        m:=fz[(l+r) div 2,2];
        mm:=fz[(l+r) div 2,1];
        repeat
            while (fz[i,2]<m) or ((fz[i,2]=m) and (fz[i,1]<mm)) do inc(i);
            while (fz[j,2]>m) or ((fz[j,2]=m) and (fz[j,1]>mm)) do dec(j);
            if i<=j then
            begin
                fz[0]:=fz[i];
                fz[i]:=fz[j];
                fz[j]:=fz[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsortt(l,j);
        if i<r then qsortt(i,r);
    end;
function efh(kx,ky:longint):longint;
    var
        l,r,mid:longint;
    begin
        l:=1;
        r:=n+2;
        while l+1<r do
        begin
            mid:=(l+r) div 2;
            if (mi[mid,1]<kx) or (mi[mid,1]=kx) and (mi[mid,2]<=ky) then l:=mid
            else r:=mid;
        end;
        efh:=l;
    end;
function efl(kx,ky:longint):longint;
    var
        l,r,mid:longint;
    begin
        l:=1;
        r:=n+2;
        while l+1<r do
        begin
            mid:=(l+r) div 2;
            if (fz[mid,2]<ky) or (fz[mid,2]=ky) and (fz[mid,1]<=kx) then l:=mid
            else r:=mid;
        end;
        efl:=l;
    end;
begin
    readln(n,m,t);
    for i:=1 to n do
    begin
        read(mi[i,2],mi[i,1]);
        read(ch);
        readln(ch);
        if ch='/' then mi[i,3]:=1
        else mi[i,3]:=2;
    end;
    sjzl;
    mi[n+1,1]:=0;
    mi[n+1,2]:=0;
    fz:=mi;
    qsort(1,n+1);
    qsortt(1,n+1);
    x:=0;
    y:=0;
    mi[n+2,1]:=t+1;
    mi[n+2,2]:=mi[n+2,1];
    fz[n+2]:=mi[n+2];
    fz[0]:=fz[n+2];
    mi[0]:=fz[0];
    fx:=4;
    123:
    while true do
    begin
        if fx mod 2=0 then uu:=efh(x,y)
        else uu:=efl(x,y);
        if (fx=1) or (fx=4) then inc(uu) else dec(uu);
        if fx mod 2=0 then
        begin
            if mi[uu,1]<>x then goto 234;
            ans:=ans+abs(mi[uu,1]-x)+abs(mi[uu,2]-y);
            x:=mi[uu,1];
            y:=mi[uu,2];
            if ans>=t then
            begin
                if fx=4 then y:=y-(ans-t)
                else y:=y+(ans-t);
                writeln(y,' ',x);
                halt;
            end;
            if (fx=4) and (mi[uu,3]=1) then fx:=1
            else if (fx=4) and (mi[uu,3]=2) then fx:=3
            else if (fx=2) and (mi[uu,3]=1) then fx:=3
            else fx:=1;
            if (mi[uu,1]=0) and (mi[uu,2]=0) then
            begin
                t:=t mod ans;
                x:=0;
                y:=0;
                fx:=4;
                ans:=0;
                goto 123;
            end;
        end
        else
        begin
            if fz[uu,2]<>y then goto 234;
            ans:=ans+abs(fz[uu,1]-x)+abs(fz[uu,2]-y);
            x:=fz[uu,1];
            y:=fz[uu,2];
            if ans>=t then
            begin
                if fx=1 then x:=x-(ans-t)
                else x:=x+(ans-t);
                writeln(y,' ',x);
                halt;
            end;
            if (fz[uu,1]=0) and (fz[uu,2]=0) then fx:=fx
            else
            if (fx=1) and (fz[uu,3]=1) then fx:=4
            else if (fx=1) and (fz[uu,3]=2) then fx:=2
            else if (fx=3) and (fz[uu,3]=1) then fx:=2
            else fx:=4;
        end;
    end;
    234:
    if fx=1 then x:=x+(t-ans);
    if fx=3 then x:=x-(t-ans);
    if fx=2 then y:=y-(t-ans);
    if fx=4 then y:=y+(t-ans);
    writeln(y,' ',x);
end.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值