解题思路:
考虑当质点移动轨迹的直线斜率为1的时候,有轨迹方程 y = x + c,显然把原先起点x1,y1代入就可以求出c的值.
将质点的反弹等价于直线轨迹(由对称性质可得)。由x - y = -c得,要使得质点可以从顶角出去就等价于质点的直线轨迹会经过一点
(a*n,b*m),代入方程得a*n - b*m = -c,要使方程有解gcd(n,m) | c, c = k*gcd(n,m),根据扩展欧几里得就可以求出方程得一个解。初始化 x = k就可以得到c的一个解,等价于gcd(n,m)*k,因为k是可以提取的所以没有影响.另t*n%m==0,那么最小正整数t就是m/gcd(n,m),所以最小的a肯定是在t之内所以a要对t求余求最小的那个坐标.
至于其他方向向量不是(1,1)的可以用过对称转化为向量(1,1)去求解.
矩形平铺在坐标轴的坐标位置有明显的规律可循,画图就可以直接看出来了.
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll x,y,c; void ex_euclid(ll a,ll b) { if(!b){ x = c; y = 0; }else{ ex_euclid(b,a%b); ll tem =x; x = y; y = tem - a/b*y; } } int main() { int n,m,x1,y1,vx,vy; scanf("%d%d%d%d%d%d",&n,&m,&x1,&y1,&vx,&vy); if(!vx&&!vy) return 0*puts("-1"); if(vx&&!vy){ if(y1==0){ if(vx==-1) printf("0 0\n"); else printf("%d 0\n",n); }else if(y1==m){ if(vx==-1) printf("0 %d\n",m); else printf("%d %d\n",n,m); }else puts("-1"); return 0; }if(!vx&&vy){ if(x1==0){ if(vy==-1) printf("0 0\n"); else printf("0 %d\n",m); }else if(x1==n){ if(vy==-1) printf("%d 0\n",n); else printf("%d %d\n",n,m); }else puts("-1"); return 0; } int fx = 0,fy = 0; if(vx==-1) fx = 1,x1 = n - x1; if(vy==-1) fy = 1,y1 = m - y1; int g = __gcd(n,m),_m = m/g; c = (x1-y1)/g; if((x1-y1)%g!=0) return 0*puts("-1"); ex_euclid(n,m); x = (x%_m + _m - 1)%_m + 1,y = -((x1-y1)-x*n)/m;//x为0时应该是_m int ansn = n,ansm = m; if(x%2==0) ansn = n - ansn; if(y%2==0) ansm = m - ansm; if(fx) ansn = n - ansn;//对称取反(坐标上的规律) if(fy) ansm = m - ansm; printf("%d %d\n",ansn,ansm); return 0; }
文章来源: Codeforces 982E - 扩展欧几里得