C. Ray Tracing
链接:
http://codeforces.com/contest/724/problem/C
题解:
把矩形对称展开,最后小球在横纵坐标均为maxx=mn/gcd(m,n)处被吸收。
原坐标为(x,y)的小球经过轴对称展开,其坐标为(2kn±x,2sm±y),k,s为整数.要使得在吸收前经过点,则坐标必须在线段(0, 0)到(INF, INF)之间。
即要解方程2kn±x=2sm±y,求为正最小的2kn±x。利用扩展欧几里得解方程。
代码:
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 5 typedef long long ll; 6 ll r, INF, a, b, n, m, k; 7 8 ll extend_gcd(ll a, ll b, ll &x, ll &y){ 9 if (b == 0) { 10 x = 1; y = 0; 11 return a; 12 } 13 else { 14 ll r = extend_gcd(b, a%b, y, x); 15 y -= x*(a / b); 16 return r; 17 } 18 } 19 20 ll solve(ll x, ll y){ 21 ll l = x + y; 22 if (l%r) return INF; 23 ll mod = -2 * m / r, k = a * l / r; 24 if (mod < 0) mod = -mod; 25 k = (k%mod + mod) % mod; 26 long long ret = 2 * n*k - x; 27 if (ret > 0 && ret < INF) return ret; 28 else return INF; 29 } 30 31 int main() 32 { 33 cin >> n >> m >> k; 34 r = extend_gcd(n, m, a, b); 35 INF = n*m / r + 1; 36 r = extend_gcd(2 * n, -2 * m, a, b); 37 while (k--) { 38 ll x, y; 39 cin >> x >> y; 40 ll ans = INF; 41 ans = min(ans, solve(x, y)); 42 ans = min(ans, solve(x, -y)); 43 ans = min(ans, solve(-x, y)); 44 ans = min(ans, solve(-x, -y)); 45 if (ans != INF) cout << ans << endl; 46 else cout << -1 << endl; 47 } 48 return 0; 49 }