1. 程式人生 > >codeforces724c Ray Tracing(擴充套件歐幾里得)

codeforces724c Ray Tracing(擴充套件歐幾里得)

題意:從(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;
}