C. Ray Tracing——披着搜索外衣的扩展欧几里得

【题目大意】

给你一个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 }

 

你可能感兴趣的:(C. Ray Tracing——披着搜索外衣的扩展欧几里得)