Yukicoder062 リベリオン

問題概要

二次元平面上$(H,W)$で、弾丸が発射される。的が$Q$個あり、それぞれにhitするかを判定せよ。

$Q\leqq10^4$、$H,W\leqq10^9$、(諸所の制限)$\leqq10^9$

yukicoder061

解法

多倍長整数には気をつけよう!ということでPython一択が良さそう。
考慮すべき点は次の通り。
反射を考えないときは4つの領域が無限に隣接した世界で考えることになる。故にtargetは4種類の点のみ考えれば良い。
どの点に、何番目の点に衝突するかを全探索はできないので、パラメーターを特定できれば良い。
衝突条件を整理し、衝突時刻がD以下かを判定すれば良い。
c++自前BigIntによって定数倍がとても大きいのでとても頑張るのと、extgcdが負を返す実装のときはnormalizeするのを忘れない。

計算量: 定数倍がヤバい、$O(Qlog(W*H))$

ソース

    #include <bits/stdc++.h>
    using namespace std;
    
    #define FOR(i, s, e) for (int(i) = (s); (i) < (e); (i)++)
    
    struct BigInt {
    public:
        using LL = long long int;
        static const LL BASE = 1000000000;
        const int DIG = 9;
    
        bool neg;
        std::vector<LL> dig;
    
        BigInt() : neg(false), dig(1, 0ll) {}
        BigInt(const char* str) : BigInt(std::string(str)) {}
        BigInt(const std::string& str) : neg(false) {
            if (str.empty()) {
                dig.assign(1, 0);
                return;
            }
    
            int b = 0;
            if (str[b] == '-') {
                neg = true;
                ++b;
            }
    
            LL crt = 0;
            LL p = 1;
            for (int i = (int)(str.size()) - 1; i >= b; --i, p *= 10) {
                if (p == BASE) {
                    dig.emplace_back(crt);
                    crt = 0;
                    p = 1;
                }
                if (!isdigit(str[i])) {
                    throw "Non digit is given.";
                }
                crt += p * (str[i] - '0');
            }
            dig.emplace_back(crt);
            norm();
        }
        BigInt(LL x) : neg(x < 0), dig(1, std::abs(x)) {
            for (unsigned int i = 0; i < dig.size(); ++i) {
                if (dig[i] >= BASE) {
                    dig.emplace_back(dig[i] / BASE);
                    dig[i] %= BASE;
                }
            }
        }
        BigInt& operator=(const BigInt& rhs) {
            neg = rhs.neg;
            dig = rhs.dig;
            return *this;
        }
        BigInt& operator=(LL x) { return *this = BigInt(x); }
        BigInt& operator=(const char* s) { return *this = BigInt(s); }
        BigInt& operator=(const std::string& s) { return *this = BigInt(s); }
    
        bool iszero() const {
            return dig.size() == 1 && dig[0] == 0;
        }
    
        BigInt operator-() const {
            BigInt res = *this;
            if (!res.iszero())
                res.neg = !res.neg;
            return res;
        }
    
        //! ignoring sign
        static int comp(const BigInt& l, const BigInt& r) {
            if (l.dig.size() != r.dig.size())
                return (l.dig.size() < r.dig.size() ? -1 : 1);
    
            for (int i = (int)(l.dig.size()) - 1; i >= 0; --i) {
                if (l.dig[i] != r.dig[i])
                    return (l.dig[i] < r.dig[i] ? -1 : 1);
            }
            return 0;
        }
        //! add ignoring sign
        static void add(BigInt& l, const BigInt& rhs) {
            unsigned int i;
            for (i = 0; i < rhs.dig.size(); ++i) {
                if (l.dig.size() <= i) {
                    l.dig.emplace_back(rhs.dig[i]);
                }
                else {
                    l.dig[i] += rhs.dig[i];
                    if (l.dig[i] >= BASE) {
                        l.dig[i] -= BASE;
                        if (l.dig.size() <= i + 1)
                            l.dig.emplace_back(0);
                        l.dig[i + 1]++;
                    }
                    else if (l.dig[i] < 0) {
                        l.dig[i] += BASE;
                        if (l.dig.size() <= i + 1)
                            l.dig.emplace_back(0);
                        l.dig[i + 1]--;
                    }
                }
            }
            for (; i < l.dig.size(); ++i)
                if (l.dig[i] >= BASE) {
                    l.dig[i] -= BASE;
                    if (l.dig.size() <= i + 1)
                        l.dig.emplace_back(0);
                    l.dig[i + 1]++;
                }
        }
        // subtract ignoring sign, supposed to l >= rhs
        static void sub(BigInt& l, const BigInt& rhs) {
            unsigned int i;
            for (i = 0; i < rhs.dig.size(); ++i) {
                l.dig[i] -= rhs.dig[i];
                if (l.dig[i] < 0) {
                    l.dig[i] += BASE;
                    l.dig[i + 1]--;
                }
            }
            for (; i < l.dig.size(); ++i)
                if (l.dig[i] < 0) {
                    l.dig[i] += BASE;
                    l.dig[i + 1]--;
                }
        }
    
        void flip() {
            for (unsigned int i = 0; i < dig.size(); ++i)
                dig[i] *= -1;
        }
        void norm() {
            while (dig.size() > 1 && dig.back() == 0) dig.pop_back();
            if (iszero()) neg = false;
        }
        bool operator==(const BigInt& rhs) const {
            if (neg != rhs.neg || dig.size() != rhs.dig.size()) return false;
            return comp(*this, rhs) == 0;
        }
        bool operator<(const BigInt& rhs) const {
            if (neg != rhs.neg) return neg ? true : false;
            if (neg) return comp(rhs, *this) == -1;
            return comp(*this, rhs) == -1;
        }
        bool operator<=(const BigInt& rhs) const {
            if (neg != rhs.neg) return neg ? true : false;
            if (neg) return comp(rhs, *this) <= 0;
            return comp(*this, rhs) <= 0;
        }
        bool operator!=(const BigInt& rhs) const { return !(*this == rhs); }
        bool operator>(const BigInt& rhs)  const { return rhs < *this; }
        bool operator>=(const BigInt& rhs) const { return rhs <= *this; }
    
        // ignoring sign
        void incl() {
            for (unsigned int i = 0; i < dig.size(); ++i)
                if (++dig[i] == BASE) {
                    dig[i] = 0;
                    if (i + 1 == dig.size()) {
                        dig.push_back(1);
                        break;
                    }
                }
                else break;
        }
        // ignoring sign
        void decl() {
            if (iszero()) {
                dig[0] = 1;
                neg = true;
                return;
            }
            for (unsigned int i = 0; i < dig.size(); ++i)
                if (--dig[i] == -1)
                    dig[i] = BASE - 1;
                else break;
                norm();
        }
        BigInt& operator++() {
            if (!neg) incl(); else decl();
            return *this;
        }
        BigInt operator++(int) {
            BigInt res = *this;
            if (!neg) incl(); else decl();
            return res;
        }
        BigInt& operator--() {
            if (!neg) decl(); else incl();
            return *this;
        }
        BigInt operator--(int) {
            BigInt res = *this;
            if (!neg) decl(); else incl();
            return res;
        }
    
        BigInt& operator+=(const BigInt& rhs) {
            if (!this->neg) {
                if (!rhs.neg)
                    add(*this, rhs);
                else {
                    if (comp(*this, rhs) >= 0)
                        sub(*this, rhs);
                    else {
                        flip();
                        add(*this, rhs);
                        neg = true;
                    }
                }
            }
            else {
                if (!rhs.neg) {
                    if (comp(rhs, *this) >= 0) {
                        flip();
                        add(*this, rhs);
                        neg = false;
                    }
                    else
                        sub(*this, rhs);
                }
                else
                    add(*this, rhs);
            }
    
            norm();
            return *this;
        }
        BigInt& operator-=(const BigInt& rhs) { return *this += -rhs; }
        BigInt operator+(const BigInt& rhs) const { BigInt res = *this; return res += rhs; }
        BigInt operator-(const BigInt& rhs) const { BigInt res = *this; return res -= rhs; }
        BigInt operator*(const BigInt& rhs) const {
            BigInt res;
            res.dig.assign(dig.size() + rhs.dig.size() + 1, 0ll);
            res.neg = neg ^ rhs.neg;
    
            for (unsigned i = 0; i < rhs.dig.size(); ++i) {
                if (rhs.dig[i] == 0) continue;
                for (unsigned j = 0; j < dig.size(); ++j) {
                    res.dig[i + j] += rhs.dig[i] * dig[j];
                    if (res.dig[i + j] >= BASE) {
                        res.dig[i + j + 1] += res.dig[i + j] / BASE;
                        res.dig[i + j] %= BASE;
                    }
                }
            }
            res.norm();
    
            return res;
        }
        BigInt operator*=(const BigInt& rhs) { return *this = *this * rhs; }
    
        static void divll(BigInt& x, LL& r, LL d) {
            bool lneg = x.neg;
            x.neg ^= (d < 0);
            if (d < 0) d *= -1;
    
            r = 0;
            for (int i = (int)x.dig.size() - 1; i >= 0; --i) {
                r = r * BASE + x.dig[i];
                x.dig[i] = r / d;
                r %= d;
            }
            x.norm();
    
            if (r != 0 && lneg)
                r *= -1;
        }
    
        void powB(LL x) {
            if (iszero()) return;
            while (x > 0) {
                dig.insert(dig.begin(), 0ll);
                --x;
            }
        }
        static void divmod(BigInt& q, BigInt& r, const BigInt& lhs, const BigInt& rhs) {
            int cmp = comp(lhs, rhs);
            if (cmp < 0) {
                q.dig = std::vector<LL>(1, 0ll);
                q.neg = false;
                r = lhs;
                return;
            }
            else if (cmp == 0) {
                q.dig = std::vector<LL>(1, 1ll);
                q.neg = false;
                r.dig = std::vector<LL>(1, 0ll);
                r.neg = false;
                return;
            }
            if (rhs.dig.size() == 1) {
                LL rl;
                q = lhs;
                divll(q, rl, rhs.dig[0] * (rhs.neg ? -1ll : 1ll));
                r = rl;
                return;
            }
    
            q.neg = r.neg = false;
    
            int u = lhs.dig.size() - rhs.dig.size() + 1;
            q.dig.assign(u + 1, 0ll);
    
            LL K = BASE / (rhs.dig.back() + 1);
            BigInt ltmp = lhs, rtmp = rhs;
            ltmp.neg = rtmp.neg = false;
    
            if (K > 1) {
                ltmp *= K;
                rtmp *= K;
            }
    
            LL x = ltmp.dig.back() / rtmp.dig.back();
            if (x == 0) {
                --u;
                x = (ltmp.dig.back() * BASE + ltmp.dig[ltmp.dig.size() - 2]) / rtmp.dig.back();
            }
            BigInt w = 0ll;
            while (true) {
                w = rtmp;
                w.powB(u);
                if (comp(w, ltmp) > 0) {
                    --u;
                    continue;
                }
                while (true) {
                    w = rtmp * x;
                    w.powB(u);
                    if (comp(w, ltmp) <= 0) break;
                    --x;
                }
    
                q.dig[u--] = x;
                ltmp -= w;
                if (ltmp == 0ll || u < 0) break;
    
                x = std::min(BASE - 1,
                    (ltmp.dig.back() * BASE + ltmp.dig[ltmp.dig.size() - 2]) / rtmp.dig.back());
            }
            q.norm();
    
            r = ltmp;
            if (ltmp != 0ll) divll(r, x, K);
            q.neg = lhs.neg ^ rhs.neg;
            r.neg = lhs.neg;
            r.norm();
        }
    
        BigInt operator/(const BigInt& rhs) const {
            BigInt q, r;
            divmod(q, r, *this, rhs);
            return q;
        }
        BigInt operator%(const BigInt& rhs) const {
            BigInt q, r;
            divmod(q, r, *this, rhs);
            return r;
        }
        BigInt& operator/=(BigInt rhs) { return *this = *this / rhs; }
        BigInt& operator%=(BigInt rhs) { return *this = *this % rhs; }
    
        std::string to_string() const {
            //assert(!dig.empty());
            std::string res = neg ? "-" : "";
    
            std::ostringstream os;
            os << std::to_string(dig.back());
            for (int i = (int)(dig.size()) - 2; i >= 0; --i) {
                os << std::setfill('0') << std::setw(DIG) << dig[i];
            }
            res += os.str();
            return res;
        }
        // convert long long int anyway
        LL to_ll() const {
            LL res = 0, p = 1;
            for (unsigned int i = 0; i < dig.size(); ++i) {
                res += dig[i] * p;
                p *= BASE;
            }
            return res * (neg ? -1ll : 1);
        }
    
    
    };
    
    int xx = 0;
    BigInt zero(xx);
    
    BigInt gcd(const BigInt &a, const BigInt &b) {
        return b == zero ? a : gcd(b, a % b);
    }
    // 拡張ユークリッド互除法 a*x+b*y=1となる整数解x,yを求める
    // 返却値: gcd(a,b)
    BigInt extgcd(BigInt a, BigInt b, BigInt &x, BigInt &y) {
        BigInt gcd_ = a;
        if (!b.iszero()) {
            gcd_ = extgcd(b, a%b, y, x);
            y -= (a / b)*x;
        }
        else {
            x = 1; y = zero;
        }
        return gcd_;
    }
    std::ostream& operator<<(std::ostream& os, const BigInt& x) { return os << x.to_string(); }
    std::istream& operator>>(std::istream& is, BigInt& x) { string s; is >> s; x = s; return is; }
    BigInt W, H, D, Mx, My, Hx, Hy, Vx, Vy;
    
    
    int f(BigInt tx, BigInt ty) {
        BigInt A = W * 2 * Vy;
        BigInt B = -H * 2 * Vx;
        BigInt C = ty*Vx - tx*Vy + Hx*Vy - Hy*Vx;
        BigInt g = gcd(A, -B);
    
        if (!(C % g).iszero()) {
            return 0;
        }
        A /= g; B /= g; C /= g;
        BigInt x, y;
        g = extgcd(B, A, y, x);
        if (g < zero) {
            g *= -1; y *= -1; x *= -1;
        }
        BigInt m = C*y%A;
        BigInt tv = (ty + H*m * 2 - Hy) / Vy;
        tv = tv % (H * 2 * A / Vy);
        if (tv < zero)tv += H * 2 * A / Vy;
        return (tv <= D);
    }
    
    int main() {
        cin.tie(0);
        ios_base::sync_with_stdio(false);
    
        int Q; cin >> Q;
        FOR(q, 0, Q) {
            cin >> W >> H >> D >> Mx >> My >> Hx >> Hy >> Vx >> Vy;
            if (Vx < zero) {
                Mx = W - Mx;
                Hx = W - Hx;
                Vx = -Vx;
            }
            if (Vy < zero) {
                My = H - My;
                Hy = H - Hy;
                Vy = -Vy;
            }
    
            int res = 0;
            if (Vx == zero) {
                if (Mx == Hx && ((My > Hy && My - Hy <= D*Vy) || (My < Hy && H * 2 - My - Hy <= D*Vy))) {
                    res = 1;
                }
                else {
                    res = -1;
                }
            }
            else if (Vy == zero) {
                if (My == Hy && ((Mx > Hx && Mx - Hx <= D*Vx) || (Mx < Hx && W * 2 - Mx - Hx <= D*Vx))) {
                    res = 1;
                }
                else {
                    res = -1;
                }
            }
            if (res) {
                if (res == 1)printf("Hit\n");
                else printf("Miss\n");
            }
            else {
                BigInt g = gcd(Vx, Vy);
                D *= g;
                Vx /= g, Vy /= g;
                if (f(Mx, My) || f(W * 2 - Mx, My) || f(Mx, H * 2 - My) || f(W * 2 - Mx, H * 2 - My)) {
                    res = 1;
                }
                if (res == 1)printf("Hit\n");
                else printf("Miss\n");
            }
    
        }
    
        return 0;
    }
Share Comments
̃Gg[͂ĂȃubN}[Nɒlj
comments powered by Disqus