[ACMICPC 2014 Beijing Onsite] C Collision

数学 专栏收录该内容
2 篇文章 0 订阅

Collision

题目大意

给一个 P*Q 的矩形,两个小球分别以 (1 , 1) 的方向在 (a,x) (b,y) 点开始运动,碰到墙壁依照镜面反射。问是否能相遇如果相遇输出第一个相遇地点。

做法

这个题目首先请看我出过的一个题目:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2087 。

我们先看 X 坐标,因为小球的速度不变,很容易能得到每个球在行走 2*P 的距离之后对于 X 坐标来说,他们相遇的时刻是一个循环。也就是一定会在 (2k)*P+U 和 (2k*Q) + V 处相遇。对于 Y 坐标亦然。那我们就来计算 U 和 V 的位置。

首先我们把问题抽象为一维的问题—— 有一个 0~P 的坐标轴,有两个质点在 a 和 b (a<b),速度都是 1 , 碰到端点原速返回。

那么第一个相遇的情况U: A 点走了一段距离还没有到 P 点,而 B 点走了一段距离碰到 P 点之后折回一段距离碰到了 A 点。

如果设时间为 t , 很容易列出一个方程 ——   a+t <相遇点的坐标U> = P - (b+t-P <折回的距离>)<相遇点的坐标U> , 化简为: t = P - (a + b)/2 。因此下一次在 U 点相遇的时间为 t + 2*P(两个球又同时走了一个折回相遇) , t + 4 * P ...... t + (2k)*P

对于第二个相遇的情况V: A 点走了一段距离碰到 P 之后折回没有碰到 0 点之前与 B 相遇。 B 碰到 P 之后折回,又碰到 0 之后又折回,再碰到 A。

如果设时间为t , 很容易列出一个方程 ——  P-(a+t-P<V 点距离P点距离>)<V点坐标> = (b+t - 2*P) ,化简为:t = 2P - (a + b)/2 。 因此下一次在 V 点相遇的时间为 t + 2*P(两个球又同时走了一个折回相遇) , t + 4 * P ...... t + (2k)*P.

我们看现在就有一个很好的性质!!!那就是相遇的时间可以简化为 t = P - (a+b)/2 + k*P (k >= 0) 

同理可得,对于 Y 坐标,相遇时间可以简化为 : t = Q - (x+y)/2 + kk * Q (kk >= 0)

联立两个方程,化简可得:k*P - kk * Q = (P - Q) - ( (a+b) / 2 - (x + y) / 2)

那么我们就肯容易发现这个东西的长相不是 Ax + By + C = 0 么???!!! 这是啥?扩展GCD啊!

我们设 C = (P - Q ) - ( (a+b)  / 2 - (x + y) / 2) , A = P , B = -Q . 然后利用 扩展 GCD 求出一组解。因为他要求第一个相遇位置,那么我们就调整一下答案,求出最小整数解就好了呀。

但是这个题目还有几个坑:

0. 因为等式左边是整数,那么右边必须也是整数。所以如果 C 不是整数,输出 No 就好了。

1. 如果a=b , x=y的话,那么一开始就相遇了,因此直接输出 (a,x) 点即可。

2. 如果a=b , x=y的话,只用看X坐标或者Y坐标即可,输出第一个出现的位置就行了。

3. 我们知道 k*P - kk*Q 能形成的最小正整数解是 GCD(P,Q) , 那么如果 C 不是 GCD(P,Q) 的倍数的话输出 NO就行了。

4. 对于最普遍的情况,我们按照 C 的正|负分类。以正数为例,设 r = extendGCD(P , -Q , n , m) ,那么一组普通的解就是 k = n * C / r , kk = m * C / r . 然后我们按照 P 和 Q 的倍数进行调整(见 f 函数)。我们得到最小解 k 之后(代码里面是 pp ) , 那么我们带入原式就能得到行走的时间 t 。 然后分别在 P 和 Q 上映射到坐标即可。


Code(写的又臭又长真是抱歉 T^T

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>

using namespace std;

#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )

#define ALL(A) A.begin(), A.end()
#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())
#define CTN(T, x) (T.find(x) != T.end())
#define SZ(A) int(A.size())
#define PB push_back
#define MP(A, B) make_pair(A, B)
#define fi first
#define se second

typedef long long LL;


typedef vector<int> VI;
typedef map<int, int> MII;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;



template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}
template<class T> inline void CLR(T &A){A.clear();}

//}

/** Constant List .. **/ //{

const int dx4[] = {-1, 0, 1, 0};
const int dy4[] = {0, 1, 0, -1};

const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};
const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};

const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};
const int dyhorse[] = {1 ,  -1 , 2  , -2 , 2 ,-2 , 1 ,-1};

const int MOD = 1000000007;
//int MOD = 99990001;
const int INF = 0x3f3f3f3f;
const LL INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;

//}

template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}
template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}
//}
template<class T> inline T low_bit(T x) {return x & -x;}

/*****************************************************************/
typedef long long typec;
typedef double DB;
const DB eps = 1e-9;
int dblcmp(DB d){
    return d < -eps ? -1 : d > eps;
}
typec GCD(typec a, typec b)
{
    return b ? GCD(b, a % b) : a;
}
typec extendGCD(typec a, typec b, typec& x, typec& y)
{
    if(!b) return x = 1, y = 0, a;
    typec res = extendGCD(b, a % b, x, y), tmp = x;
    x = y, y = tmp - (a / b) * y;
    return res;
}
void f(DB &x , DB &y , LL ax , LL ay){
    if (x > eps){
        DB add = (x - fmod(x , (DB)abs(ax)) ) / abs(ax);
        if (ax > 0){
            x -= add * ax;
            y -= add * ay;
        }
        else{
            x += add * ax;
            y += add * ay;
        }
    }
    if (y < -eps){
//        LL add = (-y) / abs(ay) + ((-y) % abs(ay) != 0);
        DB add = (-y - fmod(-y , (DB)abs(ay)) ) / (DB)abs(ay) + (dblcmp(fmod(-y , DB(abs(ay)))) != 0);
        if (ay > 0){
            x += add * ax;
            y += add * ay;
        }
        else{
            x -= add * ax;
            y -= add * ay;
        }
    }
    if (x < -eps){
//        LL add = (-x) / abs(ax) + ((-x) % abs(ax) != 0);
        DB add = (-x - fmod(-x , (DB)abs(ax)) ) / (DB)abs(ax) + (dblcmp(fmod(-x , DB(abs(ax)))) != 0);
        if (ax > 0){
            x += add * ax;
            y += add * ay;
        }
        else{
            x -= add * ax;
            y -= add * ay;
        }
    }
}
LL P , Q , a , b , x , y;
int Case;
void solve(){
    scanf("%I64d%I64d%I64d%I64d%I64d%I64d" , &P , &Q , &a , &x , &b , &y);
    if (a == b && x == y){
        printf("Case #%d:\n" , ++Case);
        printf("%.1lf %.1lf\n" , 1. * a , 1. * x);
        return;
    }
    if (a == b){
        printf("Case #%d:\n" , ++Case);
        DB t = Q - 1. * (x + y) / 2.;
        DB ans = a + t;
        ans = fmod(ans , 2. * P);
        if (dblcmp(ans - P) >= 0) ans = 2. * P - ans;
        printf("%.1lf " , ans);
        ans = y + t;
        ans = fmod(ans , 2. * Q);
        if (dblcmp(ans - Q) >= 0) ans = 2. * Q- ans;
        printf("%.1lf\n" , ans);
        return;
    }
    if (x == y){
        printf("Case #%d:\n" , ++Case);
        DB t = P - 1. * (a + b) / 2.;
        DB ans = a + t;
        ans = fmod(ans , 2. * P);
        if (dblcmp(ans - P) >= 0) ans = 2. * P - ans;
        printf("%.1lf " , ans);
        ans = y + t;
        ans = fmod(ans , 2. * Q);
        if (dblcmp(ans - Q) >= 0) ans = 2. * Q - ans;
        printf("%.1lf\n" , ans);
        return;
    }
    if (abs(a + b - x - y) % 2 == 1){
        printf("Case #%d:\nCollision will not happen.\n" , ++Case);
        return;
    }
    LL C = Q - P + (a + b - x - y) / 2;
    if (C % __gcd(P , Q) != 0){
        printf("Case #%d:\nCollision will not happen.\n" , ++Case);
        return;
    }
    LL n , m;
    printf("Case #%d:\n" , ++Case);
//    cout << C << endl;
    if (C >= 0){
        LL r = extendGCD(P , -Q , n , m);
        LL multi = C / r;
        DB pp = n , qq = m ;
        pp *= multi , qq *= multi;
    //    cout << p << ' ' << q;
        f(pp , qq , Q / r , P / r);
//        cout << pp << ' ' << qq << endl;
        DB ans = pp * P + P - 1. * (a + b) / 2.;
        ans += a;
        ans = fmod(ans , 2. * P);
        if (dblcmp(ans - P) >= 0) ans = 2. * P - ans;
        printf("%.1lf " , ans);
        ans = qq * Q + Q - 1. * (x + y) / 2.;
        ans += x;
        ans = fmod(ans , 2. * Q);
        if (dblcmp(ans - Q) >= 0) ans = 2. * Q - ans;
        printf("%.1lf\n" , ans);
    }
    else{
        LL r = extendGCD(Q , -P , m , n);
        LL multi = -C / r;
        DB pp = n , qq = m ;
        pp *= multi , qq *= multi;
    //    cout << p << ' ' << q;
        f(qq , pp , P / r , Q / r);
        DB ans = 0;
//        cout << pp << ' ' << qq << endl;
        ans = pp * P + P - 1. * (a + b) / 2.;
        ans += a;
        ans = fmod(ans , 2. * P);
        if (dblcmp(ans - P) >= 0) ans = 2. * P - ans;
        printf("%.1lf " , ans);
        ans = qq * Q + Q - 1. * (x + y) / 2.;
        ans += x;
        ans = fmod(ans , 2. * Q);
        if (dblcmp(ans - Q) >= 0) ans = 2. * Q - ans;
        printf("%.1lf\n" , ans);

    }
}
int main(){
    Case = 0;
    int _;
    cin >> _;
    while(_--) solve();
}


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

buaads

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值