【NOIP2016提高A组模拟】小W学物理

本文介绍了一个通过模拟光线在二维坐标系中遇到不同类型的镜子后反射路径的问题。利用排序和模拟的方法来确定光线行走特定距离后的最终位置。

Description

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

Solution

排序之后,处理上下左右,然后直接模拟一下就好了。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
typedef long long ll;
ll i,j,k,t,n,m,x,y,h,fang,xx,yy,hh,tt,chu;
int up[maxn],down[maxn],l[maxn],r[maxn],xa[maxn],ya[maxn],cc[maxn];
bool bz[maxn][4],az;
ll ans1,ans2,sum;
char s[3];
struct node{
    int a,b,c,d;
}a[maxn];
bool cmp(node x,node y){
    return x.a<y.a||x.a==y.a&&x.b<y.b;
}
bool cmp1(node x,node y){
    return x.b<y.b||x.b==y.b&&x.a<y.a;
}
int main(){
    freopen("mir.in","r",stdin);
    freopen("mir.out","w",stdout);
    scanf("%d%d%lld",&n,&m,&tt);x=0x7fffffff;
    fo(i,1,n){
        scanf("%d%d%s",&a[i].a,&a[i].b,s);
        if(a[i].b==0&&a[i].a>0&&a[i].a<x)h=i,x=a[i].a;
        if(s[0]=='/')a[i].c=1;    
        a[i].d=i;
        xa[i]=a[i].a,ya[i]=a[i].b,cc[i]=a[i].c;
    }
    sort(a+1,a+1+n,cmp);
    fo(i,2,n)if(a[i-1].a==a[i].a)up[a[i-1].d]=a[i].d,down[a[i].d]=a[i-1].d;
    sort(a+1,a+1+n,cmp1);
    fo(i,2,n)if(a[i-1].b==a[i].b)l[a[i].d]=a[i-1].d,r[a[i-1].d]=a[i].d;
    chu=x;
    fang=0;r[n+1]=h;h=n+1;x=y=0;
    while(sum<tt){
        if(bz[h][fang]&&!az){
            k=(tt-chu)/(sum-chu);
            while(k&&((sum-chu)*k+chu>tt))k--;
            sum=chu+(sum-chu)*k;
            az=1;
        }
        bz[h][fang]=1;
        if(fang==0)hh=r[h];
        if(fang==1)hh=up[h];
        if(fang==2)hh=l[h];
        if(fang==3)hh=down[h];
        k=abs(xa[h]-xa[hh])+abs(ya[hh]-ya[h]);
        if((!hh)||(sum+k>=tt)){
            if(fang==0)x+=tt-sum;
            if(fang==1)y+=tt-sum;
            if(fang==2)x-=tt-sum;
            if(fang==3)y-=tt-sum; 
            break;   
        }
        sum+=k,x=xa[hh],y=ya[hh];h=hh;
        t=cc[hh];
        if(!t){
            if(fang==1||fang==3)fang=(fang+1)%4;
            else fang=(fang-1+4)%4;
        }
        else{
            if(fang==0||fang==2)fang=(fang+1)%4;
            else fang=(fang-1+4)%4;    
        }
    }
    printf("%lld %lld\n",x,y);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值