Problem:
Score: 500 points

Problem Statement

We have caught N sardines. The deliciousness and fragrantness of the i-th sardine is A_i and B_i, respectively.

We will choose one or more of these sardines and put them into a cooler. However, two sardines on bad terms cannot be chosen at the same time.

The i-th and j-th sardines (i \neq j) are on bad terms if and only if A_i \cdot A_j + B_i \cdot B_j = 0.

In how many ways can we choose the set of sardines to put into the cooler? Since the count can be enormous, print it modulo 1000000007.

Constraints

All values in input are integers.

1 \leq N \leq 2 \times 10^5

-10^{18} \leq A_i, B_i \leq 10^{18}

Input

Input is given from Standard Input in the following format:

N
A_1 B_1
:
A_N B_N

Output

Print the count modulo 1000000007.

Sample Input 1

3
1 2
-1 1
2 -1

Sample Output 1

5

There are five ways to choose the set of sardines, as follows:

The 1-st

The 1-st and 2-nd

The 2-nd

The 2-nd and 3-rd

The 3-rd

Sample Input 2

10
3 2
3 2
-1 1
2 -1
-3 -9
-8 12
7 7
8 1
8 2
8 4

Sample Output 2

479

Solution in C++ (GCC 9.2.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;
using P_rep= pair<int64_t, int64_t>;

constexpr int64_t MOD= 1000000007;
constexpr bool is_FACTORIAL_STORED= false; // 階乗を配列に格納をする前処理をする/しない
constexpr int Nfac= is_FACTORIAL_STORED ? 2000007
                                        : 0;
/* 剰余環 Z/nZ */
struct mint{ // Z/nZ に関する演算(n:素数の場合は除算も)をサポートする構造体
  int64_t rep; // 出力すべき代表元 rep \in {0,1,..,MOD- 1}
  mint(int64_t x=0): rep(((x%MOD)+ MOD)% MOD){}
  mint operator-() const { return mint(-rep);}
  mint& operator+=(const mint& x){
    rep+= x.rep; 
    if(rep>= MOD) rep-= MOD;
    return *this;
  }
  mint& operator-=(const mint& x){
    rep-= x.rep;
    if(rep< 0) rep+= MOD;
    return *this;
  }
  mint& operator*=(const mint& x){
    rep*= x.rep; rep%= MOD;
    return *this;
  }
  mint operator+(const mint x) const {
    mint ans(*this);
    ans+= x;
    return ans;
  }
  mint operator-(const mint x) const {
    mint ans(*this);
    ans-= x;
    return ans;
  }
  mint operator*(const mint x) const {
    mint ans(*this);
    ans*= x;
    return ans;
  }
  bool operator==(const mint x) const {
    return rep==x.rep;
  }
  bool operator!=(const mint x) const {
    return rep!=x.rep;
  }

  mint pow(int64_t d) const{ // d \geq 0
    mint ans= 1;
    mint x= *this;
    while(d > 0){
      if(d&1){ ans*= x; }
      d >>= 1;
      x*= x;
    }

    return ans;
  }

  friend istream& operator >> (istream &is, mint& x) noexcept{
    int64_t a;
    is >> a;
    x= a;
    return is;
  }
  friend ostream& operator << (ostream &os, const mint& x) noexcept{
      return os << x.rep;
  }
  // MOD が素数(<=> Z/nZ が体)のとき
  mint inv() const{
    return pow(MOD-2);
  }
  mint& operator/=(const mint& x){
    *this *= x.inv();
    return *this;
  }
  mint operator/(const mint x) const {
    mint ans(*this);
    ans/= x;
    return ans;
  }
};

/* 階乗,二項係数 */
vector<mint> g_mfac(Nfac+1), g_ifac(Nfac+1);
void fact_modp_init(int N= Nfac){
  if constexpr(is_FACTORIAL_STORED){
    static bool initialized = false;
    if(!initialized){
      g_mfac.at(0)= 1;
      for(int i=1; i<=N; i++){
        g_mfac.at(i)= g_mfac.at(i-1)* (mint)i;
      }
  
      g_ifac.at(N)= g_mfac.at(N).inv();
      for(int i=N; i>0; i--){
        g_ifac.at(i-1)= g_ifac.at(i)* (mint)i;
      }

      initialized= true;
    }
    else{ return; }
  }
  else{
    return;
  }
}

inline mint mfac(int N){
  if constexpr(is_FACTORIAL_STORED){
    fact_modp_init();
    return g_mfac.at(N);
  }
  else{
    mint ans= 1;
    for(int i=1; i<=N; i++){
      ans*= (mint)i;
    }
    return ans;
  }
}

inline mint ifac(int N){
  if constexpr(is_FACTORIAL_STORED){
    fact_modp_init();
    return g_ifac.at(N);
  }
  else{
    return mfac(N).inv();
  }
}

mint binom_modp(int n, int k){
  if constexpr(is_FACTORIAL_STORED){
    if(n < 0 || min(k,n-k) < 0) return 0;
    else{
      fact_modp_init();
      return g_mfac.at(n)* g_ifac.at(k)* g_ifac.at(n-k);
    }
  }
  else{
    if(n < 0 || min(k,n-k) < 0) return 0;
    else{
      k= min(k, n-k);
      mint ans= 1;
      for(int i=1; i<=k; i++){
        ans*= (mint)(n-i+1);
      }
      ans/= mfac(k);

      return ans;
    }
  }
}

mint multiset_modp(int n, int r){
  if(n==0 && r==0) return 1;
  else{
    return binom_modp(n+r-1, r);
  }
}
// ^^^ テンプレここまで ^^^

P_rep canonical(int64_t x, int64_t y){
  if(x < 0){
    x*= -1;
    y*= -1;
  }
  int64_t g= gcd(abs(x), abs(y));

  return make_pair(x/g, y/g);
}

int main(){
  int N;
  cin >> N;

  map<P_rep, int64_t> data;
  int64_t x,y;
  mint Norigin= 0;
  for(int i=0; i<N; i++){
    cin >> x >> y;
    if(!(x==0LL && y==0LL)){
      P_rep p_this= canonical(x, y);
      
      if(data.count(p_this)){ data.at(p_this)+= 1; }
      else                  { data[p_this]= 1; }
    }
    else{
      Norigin+= 1;
    }
  }

  set<P_rep> checked;
  mint ans= 1;
  for(auto elem:data){
    P_rep p_this;
    int64_t cnt;
    tie(p_this, cnt)= elem;

    int64_t x_rep,y_rep;
    tie(x_rep, y_rep)= p_this;
    
    P_rep p_vert= (y_rep <= 0LL) ? make_pair(-y_rep,  x_rep)
                                 : make_pair( y_rep, -x_rep);
    if(!checked.count(p_this)){
      if(data.count(p_vert)){
        ans*= (mint)(((mint)2).pow(cnt)+ ((mint)2).pow(data.at(p_vert))- 1);
        checked.insert(p_vert);
      }
      else{
        ans*= ((mint)2).pow(cnt);
      }
    }
  }
  ans-= 1; // 0匹選ぶパターンは除外
  ans+= Norigin; // 原点にあるイワシの内の1匹を選ぶパターンもありえる

  cout << ans << endl;
}