又一次遇到了碰撞类的题目,还是扩展gcd和同余模方程。上次博客的链接在这:http://www.cnblogs.com/zzyDS/p/5874440.html。
现在干脆解同余模直接按照套路来吧,如果有解,那么x先乘以(c/g),然后mod数是(b/g),就按照这个套路来好了- -。
这题的思路大概是这样的,首先碰到墙壁的角肯定会在lcm(n,m)时刻发生,这之后是原路返回的,也就是说如果在这个时间之前都没有碰到的点一定是永远碰不到的。
对每一个点(x0,y0)来说,解 2nx+(-)x0 = 2ny+(-)y0。其中x和y是变量,那么移项以后显然是同余模方程。我们关于x0和y前的符号作一下讨论,解四个方程,取最小即可。
具体代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <iostream> 5 using namespace std; 6 typedef long long ll; 7 8 ll n,m,k; 9 ll maxn; 10 11 void ex_gcd(ll a,ll b,ll &x,ll &y,ll &g) 12 { 13 if(!b) {x=1;y=0;g=a;return;} 14 ex_gcd(b,a%b,y,x,g); 15 y -= a/b*x; 16 } 17 18 ll work(ll dx,ll dy) 19 { 20 ll g,x,y; 21 ex_gcd(2*n,2*m,x,y,g); 22 ll c = dy - dx; 23 if(c % g) return maxn+1; 24 25 x *= (c/g); 26 ll mod = 2*m / g; 27 x = (x%mod + mod) % mod; 28 29 ll temp = 2*n*x + dx; 30 if(temp<0 || temp>maxn) return maxn+1; 31 else return temp; 32 } 33 34 ll solve(ll x,ll y) 35 { 36 ll ans = maxn + 1; 37 ans = min(ans,work(x,y)); 38 ans = min(ans,work(-x,y)); 39 ans = min(ans,work(x,-y)); 40 ans = min(ans,work(-x,-y)); 41 if(ans == maxn+1) return -1; 42 else return ans; 43 } 44 45 int main() 46 { 47 cin >> n >> m >> k; 48 ll g = __gcd(n,m); 49 maxn = n / g * m; 50 while(k--) 51 { 52 ll x,y; 53 scanf("%I64d%I64d",&x,&y); 54 printf("%I64d\n",solve(x,y)); 55 } 56 }