Ray Tracing

Ray Tracing

题目链接:http://codeforces.com/problemset/problem/724/C

拓展欧几里得

//为什么这次C题这么难啊=。=

可以观察到,光线在矩形中运动的时间为LCM(n,m),所以可以把整个矩阵扩展成LCM(n,m)*LCM(n,m)的矩阵[光线从(0,0)点一直射到(LCM(n,m),LCM(n,m))点],然后将点关于矩形的四条边变换到直线y=x上,取最小的即可。

变换后得到的点的纵坐标为2*p*n±X,横坐标为2*q*m±Y,因为要求在直线y=x上,故2*p*n±X=2*q*m±Y,移项得2*p*n-2*q*m=±X±Y。

而拓展欧几里得可以解不定方程a*x+b*y=c,其中c=GCD(a,b),令a=2*n,b=-2*m,求得x和y。

将方程a*x+b*y=c变换成2*p*n-2*q*m=±X±Y,得到p或q,求出2*p*n±X或2*q*m±Y即可。

//注意求得的p或q要为自然数

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <cmath>
 4 using namespace std;
 5 typedef long long LL;
 6 const LL INF=100000000000000000;
 7 LL GCD(LL a,LL b){
 8     return b==0?a:GCD(b,a%b);
 9 }
10 LL exGCD(LL a,LL b,LL &x,LL &y){
11     if(b==0){
12         x=1,y=0;
13         return a;
14     }
15     LL t=exGCD(b,a%b,x,y);
16     LL r=x;x=y;y=r-a/b*y;
17     return t;
18 }
19 LL LCM(LL a,LL b){
20     LL gcd=GCD(a,b);
21     return (a/gcd)*b;
22 }
23 LL n,m,k,x,y,p,q,a,b,lim,mul;
24 LL mix(LL x,LL y){
25     LL t=x-y;
26     if(t%mul!=0)return INF;
27     t/=mul;
28     p=a*t;
29     LL mod=abs((-2*m)/mul);//mod is the t of p*x*t-q*y*t=gcd*t
30     p=(p%mod+mod)%mod;
31     LL tmp=INF;
32     LL tt=2*n*p-x;
33     if(0<tt&&tt<=lim)tmp=min(tmp,tt);
34     return tmp;
35 }
36 int main(void){
37     scanf("%I64d%I64d%I64d",&n,&m,&k);
38     lim=LCM(n,m);
39     for(LL i=0;i<k;++i){
40         scanf("%I64d%I64d",&x,&y);
41         mul=exGCD(2*n,-2*m,a,b);
42         //mul=GCD(2*n,-2*m);
43         LL ans=INF;
44         ans=min(ans,mix(-x,y));
45         ans=min(ans,mix(x,y));
46         ans=min(ans,mix(-x,-y));
47         ans=min(ans,mix(x,-y));
48         if(ans<INF)printf("%I64d\n",ans);
49         else printf("-1\n");
50     }
51 }

 

posted @ 2016-10-09 21:22  barriery  阅读(252)  评论(0编辑  收藏  举报