小W学物理【NOIP2016提高A组集训第1场10.29】
2016-10-29 21:51
351 查看
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模拟不行嘛。
当时就在想,对于这些镜子,这道光线无非就两种情况。
一种就是光线在经过最后一个镜子反射时,后面已经没有镜子时,可以直接输出了。
另一种就是在一系列的反射后重新经过了原点,那么说明有了个循环,直接跳过循环,再继续模拟就好了。
然而,对于代码能力弱的我不知道如何是好,当时就想用哈希存下所有的镜子位置,然而发现并没有什么卵用。
解法
上面已经叙述了,这里就说细节。我们两个快排处理出每一个镜子它上下左右的第一个镜子是哪个。这样转移都可以O(1)的速度。
一个镜子只有四种情况,那就是光线从它上下左右飞来,我们用四个标记来记录。
一旦出现一个镜子第二次出现某一方向的光线飞来,说明就有个循环节了。
那么时间复杂度就是O(4n)。
代码
#include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int maxn=1e5+3,mo=1e5+2; struct cy{ ll x,y,num; char ch; }mir[maxn]; struct hg{ int l,r,up,down; }aro[maxn]; int n,m,way,wayn; ll ans,now,T,val,sum; bool bz[maxn][5]; bool cmp1(cy a,cy b) { return a.x<b.x||a.x==b.x&&a.y<b.y; } bool cmp2(cy a,cy b) { return a.y<b.y||a.y==b.y&&a.x<b.x; } bool cmp3(cy a,cy b) { return a.num<b.num; } void out(ll t) { if(way==1) printf("%lld %lld",mir[now].x+t,mir[now].y); else if (way==2) printf("%lld %lld",mir[now].x-t,mir[now].y); else if (way==3) printf("%lld %lld",mir[now].x,mir[now].y+t); else printf("%lld %lld",mir[now].x,mir[now].y-t); } int main() { freopen("mir.in","r",stdin); freopen("mir.out","w",stdout); scanf("%d%d%lld",&n,&m,&T); memset(mir,255,sizeof(mir)); fo(i,1,n) scanf("%lld%lld%s",&mir[i].x,&mir[i].y,&mir[i].ch),mir[i].num=i; sort(mir+1,mir+1+n,cmp1); fo(i,1,n){ if(mir[i-1].x==mir[i].x) aro[mir[i].num].down=mir[i-1].num; else aro[mir[i].num].down=mo; if(mir[i+1].x==mir[i].x) aro[mir[i].num].up=mir[i+1].num; else aro[mir[i].num].up=mo; } sort(mir+1,mir+1+n,cmp2); bool bo=false; fo(i,1,n){ if (mir[i-1].y==mir[i].y) aro[mir[i].num].l=mir[i-1].num; else aro[mir[i].num].l=mo; if (mir[i+1].y==mir[i].y) aro[mir[i].num].r=mir[i+1].num; else aro[mir[i].num].r=mo; if (mir[i].y==0&&mir[i].x>0&&!bo) bo=true,now=mir[i].num,val=mir[i].x; } if (!now) { printf("%lld 0",T); return 0; } sort(mir+1,mir+1+n,cmp3); T-=val; way=1; sum=0; bz[now][1]=true; int next; while (T){ wayn=way; if (mir[now].ch=='/') { if (way==1) next=aro[now].up,val=mir[next].y-mir[now].y,way=3; else if (way==2) next=aro[now].down,val=mir[now].y-mir[next].y,way=4; else if (way==3) next=aro[now].r,val=mir[next].x-mir[now].x,way=1; else next=aro[now].l,val=mir[now].x-mir[next].x,way=2; } else { if (way==1) next=aro[now].down,val=mir[now].y-mir[next].y,way=4; else if (way==2) next=aro[now].up,val=mir[next].y-mir[now].y,way=3; else if (way==4) next=aro[now].r,val=mir[next].x-mir[now].x,way=1; else next=aro[now].l,val=mir[now].x-mir[next].x,way=2; } if (T<=val||next==mo) { out(T); return 0; } if (!bz[next][way]) bz[next][way]=true,sum+=val,T-=val; else T=T-T/sum*sum; now=next; } }
2300+byte,我旁边的一个pascal逗逼因为快排的原因打出了5300+,看得我好爽。
还有一个打出了9000+,%%%
相关文章推荐
- JZOJ4823. 【NOIP2016提高A组集训第1场10.29】小W学物理
- JZOJ 4823. 【NOIP2016提高A组集训第1场10.29】小W学物理
- 【NOIP2016提高A组集训第1场10.29】小W学物理
- {题解}[jzoj4823] 【NOIP2016提高A组集训第1场10.29】小W学物理
- {题解}[jzoj4823] 【NOIP2016提高A组集训第1场10.29】小W学物理
- JZOJ 4823 【NOIP2016提高A组集训第1场10.29】小W学物理
- 【NOIP2016提高A组集训第1场10.29】小W学物理
- NOIP2016提高A组集训第1场【JZOJ4823】小W学物理
- JZOJ 4822. 【NOIP2016提高A组集训第1场10.29】完美标号
- 完美标号【NOIP2016提高A组集训第1场10.29】
- 【JZOJ4824】【NOIP2016提高A组集训第1场10.29】配对游戏
- 【NOIP2016提高A组集训第1场10.29】配对游戏
- JZOJ 4824. 【NOIP2016提高A组集训第1场10.29】配对游戏
- JZOJ 4822 【NOIP2016提高A组集训第1场10.29】完美标号
- 【NOIP2016提高A组集训第1场10.29】完美标号
- JZOJ4822. 【NOIP2016提高A组集训第1场10.29】完美标号
- 【NOIP2016提高A组集训第1场10.29】完美标号
- JZOJ 4822. 【NOIP2016提高A组集训第1场10.29】完美标号
- 【NOIP2016提高A组集训第1场10.29】完美标号
- 【NOIP2016提高A组模拟】小W学物理