【题目大意】
给你一个n*m的矩形,光线从(0,0)出发,沿右上方向以每秒根号2米的速度运动,碰到矩形边界就会反弹(符合物理规律的反弹),询问k个点,这些点都在矩形内部且不在矩形边界上,求光经过这些点的最小时间。如果光不会经过这个点,输出-1.
【数据范围】
0
【吐槽】
最后1个小时都砸这道题上了,一直是搜索/模拟 的思路,然而正解是扩展欧几里得。(据说模拟也是可以的,然而我不会,sro_姬树流_orz)
【题解】
把矩形对称展开,最后小球在横纵坐标均为maxx=mn/gcd(m,n)处被吸收。
原坐标为(x,y)的小球经过轴对称展开,其坐标为(2kn±x,2sm±y),k,s为整数.要使得在吸收前经过点,则坐标必须在线段(0, 0)到(maxx, mxx)之间。
即要解方程2kn±x=2sm±y,求为正最小的2kn±x。利用扩展欧几里得解方程。
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 using namespace std;
9 long long n,m,k,aa,bb,maxx;
10 inline long long read()
11 {
12 long long x=0,f=1; char ch=getchar();
13 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
14 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
15 return x*f;
16 }
17 long long exgcd(long long a,long long b,long long &x,long long &y)
18 {
19 if(b==0) {x=1; y=0; return a;}
20 long long r=exgcd(b,a%b,y,x);
21 y-=a/b*x;
22 return r;
23 }
24 long long gao(long long x,long long y)
25 {
26 long long c=x+y,dx,dy;
27 long long r=exgcd(aa,bb,dx,dy);
28 if(c%r) return maxx+1;
29 long long mo=bb/r; dx*=c/r;
30 if(mo<0) mo=-mo;
31 dx=(dx%mo+mo)%mo;
32 long long ans=2*n*dx-x;
33 if(ans<0||ans>maxx) return maxx+1;
34 return ans;
35 }
36 long long minn(long long a,long long b) {return aa:b;}
37 long long solve(long long x,long long y)
38 {
39 long long r=__gcd(n,m);
40 maxx=n*m/r;
41 long long ans=maxx+1;
42 ans=minn(ans,gao(x,y));
43 ans=minn(ans,gao(x,-y));
44 ans=minn(ans,gao(-x,y));
45 ans=minn(ans,gao(-x,-y));
46 if(ans==maxx+1) return -1;
47 else return ans;
48 }
49 int main()
50 {
51 //freopen("cin.in","r",stdin);
52 //freopen("cout.out","w",stdout);
53 n=read(); m=read(); k=read();
54 aa=2*n; bb=-2*m;
55 for(int i=1;i<=k;i++)
56 {
57 long long x=read(),y=read();
58 printf("%I64d\n",solve(x,y));
59 }
60 return 0;
61 }