codeforces724c Ray Tracing(擴充套件歐幾里得)
阿新 • • 發佈:2019-01-01
題意:從(0,0)沿(1,1)射出來一個東西,在封閉的(n,m)(n,m<1e5)矩形內撞來撞去,k(k<1e5)次詢問(a,b),問到達(a,b)的最小時間
題解:第一感覺,肯定是把該平面展開,然後在所有展開的平面中對應的點,滿足最小的dx == dy的就是解
對於橫座標,所有展開後的點的橫座標有可能是a,2*n-a,2*n+a。。。公式2*x*n ± a
縱座標類似2*y*m ± b
要撞到,滿足2*x*n ± a == 2*y*m ± b,最小的即為解
也就是說2*x*n - 2*y*m == ±(a ± b)
擴充套件歐幾里得
當然,還可以用別的方法,超級無敵大暴力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; } ///ax + by = c 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 work(LL dx, LL dy, LL M) { LL k, s; if(equation(2*n, -2*m, -dx+dy, k, s) == -1) return M + 1; LL temp = 2 * k * n + dx; if(temp < 0 || temp > M) return M + 1; return temp; } LL solve(LL x, LL y) { LL g = __gcd(n, m); ///max1肯定是滿足的解 LL max1 = 1LL * m / g * n; LL ans = max1 + 1; ans = min(ans, work(-x, -y, max1)); ans = min(ans, work(-x, y, max1)); ans = min(ans, work(x, -y, max1)); ans = min(ans, work(x, y, max1)); if(ans == max1 + 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; }
先求出到達邊上每個點的最短時間(注意方向問題)
對於每個點,只要求出從四個方向來的時間,找最小就可以了
暴力時間比擴充套件歐幾里得快。。
int a[MAX],b[MAX]; LL vis[MAX][4][4]; int main(){ int n,m,k; while(cin>>n>>m>>k){ if(n==0 && m==0) break; for(int i=0;i<k;i++){ scanf("%d",a+i); scanf("%d",b+i); } mem(vis,-1); int tmp=0; int x=0,y=0; LL ti=0; while(true){ if(tmp==0){ if((n-x)+y==m) break; if((n-x)+y<m){ vis[(n-x)+y][3][0]=ti+n-x; ti=ti+n-x; y=(n-x)+y; x=n; tmp=3; } else{ vis[x+(m-y)][2][0]=ti+m-y; ti=ti+m-y; x=x+(m-y); y=m; tmp=1; } } else if(tmp==1){ if(y-(n-x)==0) break; if(y>n-x){ vis[y-(n-x)][3][1]=ti+(n-x); ti=ti+(n-x); y=y-(n-x); x=n; tmp=2; } else{ vis[x+y][0][1]=ti+y; ti=ti+y; x=x+y; y=0; tmp=0; } } else if(tmp==2){ if(x==y) break; if(x<y){ vis[y-x][1][2]=ti+x; ti=ti+x; y=y-x; x=0; tmp=1; } else{ vis[x-y][0][2]=ti+y; ti=ti+y; x=x-y; y=0; tmp=3; } } else if(tmp==3){ if(y+x==m) break; if(y+x<m){ vis[y+x][1][3]=ti+x; ti=ti+x; y=y+x; x=0; tmp=0; } else{ vis[x-(m-y)][2][3]=ti+(m-y); ti=ti+(m-y); x=x-(m-y); y=m; tmp=2; } } } for(int i=0;i<k;i++){ LL ans=1e18; if(a[i]==b[i]){ printf("%d\n",a[i]); continue; } if((n-a[i])+b[i]>m){ if(vis[a[i]+(m-b[i])][2][3]!=-1){ ans=min(ans,vis[a[i]+(m-b[i])][2][3]+m-b[i]); } } if((n-a[i])+b[i]<m){ if(vis[b[i]+n-a[i]][3][1]!=-1){ ans=min(ans,vis[b[i]+n-a[i]][3][1]+n-a[i]); } } if(b[i]>n-a[i]){ if(vis[b[i]-(n-a[i])][3][0]!=-1){ ans=min(ans,vis[b[i]-(n-a[i])][3][0]+n-a[i]); } } if(b[i]<n-a[i]){ if(vis[a[i]+b[i]][0][2]!=-1){ ans=min(ans,vis[a[i]+b[i]][0][2]+b[i]); } } if(a[i]<b[i]){ if(vis[b[i]-a[i]][1][3]!=-1){ ans=min(ans,vis[b[i]-a[i]][1][3]+a[i]); } } if(a[i]>b[i]){ if(vis[a[i]-b[i]][0][1]!=-1){ ans=min(ans,vis[a[i]-b[i]][0][1]+b[i]); } } if(a[i]+b[i]<m){ if(vis[a[i]+b[i]][1][2]!=-1){ ans=min(ans,vis[a[i]+b[i]][1][2]+a[i]); } } if(a[i]+b[i]>m){ if(vis[a[i]-(m-b[i])][2][0]!=-1){ ans=min(ans,vis[a[i]-(m-b[i])][2][0]+(m-b[i])); } } if(ans!=1e18) printf("%I64d\n",ans); else printf("-1\n"); } } return 0; }