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 }