Language: C++

#include <bits/stdc++.h>
using namespace std;
/* typedef */
typedef long long ll;
typedef pair<double, double> pii;
/* constant */
const int INF = 1 << 30;
const ll LINF = 1LL << 50;
const int NIL = -1;
const int MAX = 10000;
const int mod = 1000000007;
const double pi = 3.141592653589;
struct mint {
    ll x;
    mint(ll x = 0):x((x % mod + mod) % mod) {}
    mint operator-() const { return mint(-x); }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod - a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t >> 1);
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }
    // for prime mod
    mint inv() const {
        return pow(mod - 2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res /= a;
    }
};
istream& operator>>(istream& is, const mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
struct combination {
    // vector size : n + 1
    vector<mint> fact, ifact;
    // precaliculation O(n)
    combination(int n):fact(n+1), ifact(n+1) {
        assert(n < mod);
        // 0! = 1;
        fact[0] = 1;
        // 1! = 0! * 1 ... n! = (n-1)! * n
        for (int i = 1; i <= n; i++) fact[i] = fact[i-1] * i;
        // 1/n! = n!^(-1)
        ifact[n] = fact[n].inv();
        // (n-1)!^(-1) = n!^(-1) * n ... 0!^(-1) = 1!^(-1) * 1
        for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i] * i;
    }
    // combination O(1)
    // nCk = n! / (k! * (n-k)!)
    //     = n! * k!^(-1) * (n-k)!^(-1)
    mint operator()(int n, int k) {
        if (k < 0 || k > n) return 0;
        return fact[n] * ifact[k] * ifact[n-k];
    }
};
/* global variables */
/* function */
int gcd(int a, int b) {
    int tmp;
    while (b) { tmp = a; a = b; b = tmp % b; }
    return a;
}
/* main */
int main(){
    int N;
    cin >> N;
    vector<pii> p;
    double a, b;
    // 以下は別々にカウント
    // (Ai, Bi) == (0, 0)
    // (Ai, Bi) == (Ai, 0)
    // (Ai, Bi) == (0, Bi)
    int cntZero = 0;
    int cntAZero = 0, cntBZero = 0;
    for (int i = 0; i < N; i++) {
        cin >> a >> b;
        if (a == 0 && b == 0) { cntZero++; }
        else if (a == 0) cntAZero++;
        else if (b == 0) cntBZero++;
        else p.push_back(pii(a, b));
    }
    for (int i = 0; i < (int)p.size(); i++) {
        double d = gcd(p[i].first, p[i].second);
        p[i].first /= d; p[i].second /= d;
    }
    // Ai / Bi or Bj / Aj を引数とするが
    // gcd(Ai, Bi)で割ってから入れるので桁崩れるのを防ぐ
    map<double, pii> mp;
    for (int i = 0; i < (int)p.size(); i++) {
        int cnt = 0;
        if (p[i].first < 0) cnt++;
        if (p[i].second < 0) cnt++;
        p[i].first = abs(p[i].first);
        p[i].second = abs(p[i].second);
        if (cnt == 1) mp[p[i].first / p[i].second].first++;
        else mp[p[i].second / p[i].first].second++;
    }
    mint two = 2;
    mint ans = 1;
    for (auto m : mp) {
        int x, y;
        // 基本的に各イワシについて選ぶか選ばないかの2通り
        // 被っているイワシはその中のいくつかを選ぶかで 2^(被り数)
        // 同じカゴに入れてはいけないイワシの集合も同様に計算
        // 一匹も選ばない選び方が2回計算されるので1引く
        tie(x, y) = m.second;
        ans *= two.pow(x) + two.pow(y) - 1;
    }
    // 片方が0の場合も計算
    ans *= two.pow(cntAZero) + two.pow(cntBZero) - 1;
    // (0, 0)の場合はどれとも一緒に選べないのでその個数分加算
    // どのイワシも選ばない1通りを引いておく
    cout << ans + cntZero - 1 << '\n';
}


Compiler output:
In file included from /usr/include/x86_64-linux-gnu/c++/14/bits/stdc++.h:58,
                 from a.cc:1:
/usr/include/c++/14/numeric: In instantiation of 'constexpr std::common_type_t<_Mn, _Nn> std::gcd(_Mn, _Nn) [with _Mn = double; _Nn = double; common_type_t<_Mn, _Nn> = double]':
a.cc:112:23:   required from here
  112 |         double d = gcd(p[i].first, p[i].second);
      |                    ~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/numeric:175:21: error: static assertion failed: std::gcd arguments must be integers
  175 |       static_assert(is_integral_v<_Mn> && is_integral_v<_Nn>,
      |                     ^~~~~~~~~~~~~~~~~~
/usr/include/c++/14/numeric:175:21: note: 'std::is_integral_v<double>' evaluates to false
In file included from /usr/include/c++/14/bits/stl_pair.h:60,
                 from /usr/include/c++/14/bits/stl_algobase.h:64,
                 from /usr/include/c++/14/algorithm:60,
                 from /usr/include/x86_64-linux-gnu/c++/14/bits/stdc++.h:51:
/usr/include/c++/14/type_traits: In instantiation of 'struct std::make_unsigned<double>':
/usr/include/c++/14/type_traits:2076:11:   required by substitution of 'template<class _Tp> using std::make_unsigned_t = typename std::make_unsigned::type [with _Tp = double]'
 2076 |     using make_unsigned_t = typename make_unsigned<_Tp>::type;
      |           ^~~~~~~~~~~~~~~
/usr/include/c++/14/numeric:182:24:   required from 'constexpr std::common_type_t<_Mn, _Nn> std::gcd(_Mn, _Nn) [with _Mn = double; _Nn = double; common_type_t<_Mn, _Nn> = double]'
  182 |       return __detail::__gcd<make_unsigned_t<_Ct>>(__m2, __n2);
      |              ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
a.cc:112:23:   required from here
  112 |         double d = gcd(p[i].first, p[i].second);
      |                    ~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/type_traits:1929:13: error: invalid use of incomplete type 'class std::__make_unsigned_selector<double, false, false>'
 1929 |     { using type = typename __make_unsigned_selector<_Tp>::__type; };
      |             ^~~~
/usr/include/c++/14/type_traits:1837:11: note: declaration of 'class std::__make_unsigned_selector<double, false, false>'
 1837 |     class __make_unsigned_selector;
      |           ^~~~~~~~~~~~~~~~~~~~~~~~