您的位置:首页 > 其它

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

2016-10-29 15:40 369 查看
传送门

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
;
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
[4],num
[4];
long long bz
[4],c
[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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: