1. 程式人生 > >Codeforces 724C Ray Tracing 擴充套件歐幾里得

Codeforces 724C Ray Tracing 擴充套件歐幾里得

標籤: 解題報告 數學

n*m的矩形內有k個點,四周有圍牆圍起來。從(0,0)45度發射小球,速度為2每次遇到牆都正常反彈,直到射到頂點被吸收。問每個點第一次被經過的時刻。

分析

把矩形對稱展開,最後小球在橫縱座標均為maxx=mn/gcd(m,n)處被吸收。
原座標為(x,y)的小球經過軸對稱展開,其座標為(2kn±x,2sm±y),k,s.要使得在吸收前經過點,則座標必須線上段(0, 0)到(maxx, mxx)之間。
即要解方程2kn±x=2sm±y,求為正最小的2kn±x。利用擴充套件歐幾里得解方程。

求ax+by=c最小正整數解,坑點:ran<0時不搞成正數會出錯!

LL equation(LL a, LL b, LL c, LL &x, LL &y)
{
    LL g = extend_Euclid(a, b, x, y);
    if(c % g) return -1;
    LL ran = b / g;
    x *= c/g;
    if(ran < 0) ran = -ran; //wa point
    x = (x%ran + ran) % ran;
    return 0;
}

程式碼

/*--------------------------------------------
 * File Name: CF 724C
 * Author: Danliwoo
 * Mail: 
[email protected]
* Created Time: 2016-10-08 23:37:05 --------------------------------------------*/
#include <bits/stdc++.h> using namespace std; #define LL long long LL n, m; LL extend_Euclid(LL a, LL b, LL &x, LL &y){ if(b==0){ x = 1; y = 0; return a; } LL r = extend_Euclid(b, a%b, y, x); y -= a/b*x; return
r; } LL equation(LL a, LL b, LL c, LL &x, LL &y) { LL g = extend_Euclid(a, b, x, y); if(c % g) return -1; LL ran = b / g; x *= c/g; if(ran < 0) ran = -ran; x = (x%ran + ran) % ran; return 0; } LL gao(LL dx, LL dy, LL M) { LL k, s; if(equation(2*n, -2*m, -dx+dy, k, s) == -1) return M + 1; LL tx = 2 * k * n + dx; if(tx < 0 || tx > M) return M + 1; return tx; } LL minL(LL a, LL b) { return a < b ? a : b; } LL solve(LL x, LL y) { LL g = __gcd(n, m); LL maxx = 1LL * m / g * n; LL ans = maxx + 1; ans = minL(ans, gao(-x, -y, maxx)); ans = minL(ans, gao(-x, y, maxx)); ans = minL(ans, gao(x, -y, maxx)); ans = minL(ans, gao(x, y, maxx)); if(ans == maxx + 1) return -1; return ans; } int main() { int k; while(~scanf("%I64d%I64d%d", &n, &m, &k)) { for(int i = 0;i < k;i++) { LL x, y; scanf("%I64d%I64d", &x, &y); printf("%I64d\n", solve(x, y)); } } return 0; }