Codeforces 982E - 扩展欧几里得

解题思路:

考虑当质点移动轨迹的直线斜率为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;
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/80540660