Problem p02679 (C++) — buggy submission, verdict: Runtime Error

#ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>

#define PI 3.14159265359
using namespace std;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define bit(n, k) (((ll)n >> (ll)k) & 1) /*nのk bit目*/
#define pb push_back
#define pf push_front
#define FI first
#define SE second
#define eb emplace_back
#define SZ(x) ((ll)(x).size())
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const long long INF = 1e+18 + 1;
// long long INF=(1LL<<31)-1;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vector<ll>> vvl;
typedef pair<ll, ll> P;
typedef tuple<ll, ll, ll> T;
typedef struct Point_Coordinates {
  ll x, y;
} point;
const ll MOD = 1000000007LL;
// ll MOD=1000000007LL;
// const ll MOD=998244353LL;
// const ll MOD=1777777777LL;
// const ll MAX_V=114514LL;
// const ll MAX = 500010LL;
const ll mod = MOD;
string abc = "abcdefghijklmnopqrstuvwxyz";
string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
vl dx = {0, 0, 1, -1};
vl dy = {1, -1, 0, 0};

// 素因数分解O(√n)
map<ll, ll> prime_factor(ll n) {
  map<ll, ll> res;
  for (ll i = 2; i * i <= n; i++) {
    while (n % i == 0) {
      res[i]++;
      n /= i;
    }
  }
  if (n != 1)
    res[n] = 1;
  return res;
}

const ll MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
// finvが階乗の逆元

// テーブルを作る前処理
void COMinit() {
  fac[0] = fac[1] = 1;
  finv[0] = finv[1] = 1;
  inv[1] = 1;
  for (ll i = 2; i < MAX; i++) {
    fac[i] = fac[i - 1] * i % MOD;
    inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
    finv[i] = finv[i - 1] * inv[i] % MOD;
  }
}

// 二項係数計算
long long COM(ll n, ll k) {
  if (n < k)
    return 0;
  if (n < 0 || k < 0)
    return 0;
  return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

ll modpow(ll a, ll n) {

  ll res = 1;
  while (n > 0) {
    if (n & 1)
      res = res * a % mod;
    a = a * a % mod;
    n >>= 1;
  }
  return res;
}

/*Eratosthenes()
ll N=2000010;
vl arr(N);
void Eratosthenes(){
        for(ll i = 0; i < N; i++){
                arr[i] = 1;
        }
        arr[1]=0;
        for(ll i = 2; i < sqrt(N); i++){
                if(arr[i]){
                        for(ll j = 0; i * (j + 2) < N; j++){
                                arr[i *(j + 2)] = 0;
                        }
                }
        }
}*/
// 素数判定O(√n)
bool is_prime(ll n) {
  for (ll i = 2; i * i <= n; i++) {
    if (n % i == 0)
      return false;
  }
  return n != 1;
}

// 約数の列挙O(√n)
vector<ll> divisor(ll n) {
  vector<ll> res;
  for (ll i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      res.push_back(i);
      if (i != n / i)
        res.push_back(n / i);
    }
  }
  return res;
}

/* SegTree<X>(n,fx,ex): モノイド(集合X, 二項演算fx,
   単位元ex)についてサイズnで構築 set(int i, X x), build():
   i番目の要素をxにセット。まとめてセグ木を構築する。O(n) update(i,x): i
   番目の要素を x に更新。O(log(n)) query(a,b):  [a,b)
   全てにfxを作用させた値を取得。O(log(n))
*/
template <typename X> struct SegTree {
  using FX = function<X(X, X)>;
  int n;
  FX fx;
  const X ex;
  vector<X> dat;
  SegTree(int n_, FX fx_, X ex_) : n(), fx(fx_), ex(ex_), dat(n_ * 4, ex_) {
    int x = 1;
    while (n_ > x) {
      x *= 2;
    }
    n = x;
  }

  void set(int i, X x) { dat[i + n - 1] = x; }
  void build() {
    for (int k = n - 2; k >= 0; k--)
      dat[k] = fx(dat[2 * k + 1], dat[2 * k + 2]);
  }

  void update(int i, X x) {
    i += n - 1;
    dat[i] = x;
    while (i > 0) {
      i = (i - 1) / 2; // parent
      dat[i] = fx(dat[i * 2 + 1], dat[i * 2 + 2]);
    }
  }

  // the minimum element of [a,b)
  X query(int a, int b) { return query_sub(a, b, 0, 0, n); }
  X query_sub(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l) {
      return ex;
    } else if (a <= l && r <= b) {
      return dat[k];
    } else {
      X vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
      X vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
      return fx(vl, vr);
    }
  }
  /* debug */
  inline X operator[](int a) { return query(a, a + 1); }
  void print() {
    for (int i = 0; i < 2 * n - 1; ++i) {
      cout << (*this)[i];
      if (i != n)
        cout << ",";
    }
    cout << endl;
  }
  /*
  使用例
  auto fx=[](int x1,int x2)->int{return max(x1,x2);};
  ll ex=0;
  SegTree<ll>rmq(n,fx,ex);*/
};

/* Trie 木： 文字の種類(char_size)、int型で0に対応する文字(base)
    insert(word): 単語 word を Trie 木に挿入する
    search(word): 単語 word が Trie 木にあるか判定する
    start_with(prefix):  prefix が一致する単語が Trie 木にあるか判定する
    count(): 挿入した単語の数を返す
    size(): Trie 木の頂点数を返す
    計算量：insert, search ともに O(M)（Mは単語の長さ）
*/
template <int char_size, int base> struct Trie {
  struct Node {       // 頂点を表す構造体
    vector<int> next; // 子の頂点番号を格納。存在しなければ-1
    vector<int> accept; // 末端がこの頂点になる単語の word_id を保存
    int c;              // base からの間隔をint型で表現したもの
    int common; // いくつの単語がこの頂点を共有しているか
    Node(int c_) : c(c_), common(0) { next.assign(char_size, -1); }
  };
  vector<Node> nodes; // trie 木本体
  int root;
  Trie() : root(0) { nodes.push_back(Node(root)); }
  // 単語の挿入
  void insert(const string &word, int word_id) {
    int node_id = 0;
    for (int i = 0; i < (int)word.size(); i++) {
      int c = (int)(word[i] - base);
      int &next_id = nodes[node_id].next[c];
      if (next_id == -1) { // 次の頂点が存在しなければ追加
        next_id = (int)nodes.size();
        nodes.push_back(Node(c));
      }
      ++nodes[node_id].common;
      node_id = next_id;
    }
    ++nodes[node_id].common;
    nodes[node_id].accept.push_back(word_id);
  }
  void insert(const string &word) { insert(word, nodes[0].common); }
  // 単語とprefixの検索
  bool search(const string &word, bool prefix = false) {
    int node_id = 0;
    for (int i = 0; i < (int)word.size(); i++) {
      int c = (int)(word[i] - base);
      int &next_id = nodes[node_id].next[c];
      if (next_id == -1) { // 次の頂点が存在しなければ終了
        return false;
      }
      node_id = next_id;
    }
    return (prefix) ? true : nodes[node_id].accept.size() > 0;
  }
  // prefix を持つ単語が存在するかの検索
  bool start_with(const string &prefix) { return search(prefix, true); }
  // 挿入した単語の数
  int count() const { return (nodes[0].common); }
  // Trie木のノード数
  int size() const { return ((int)nodes.size()); }
};

// union by size + path having
class UnionFind {
public:
  vector<ll> par; // 各元の親を表す配列
  vector<ll> siz; // 素集合のサイズを表す配列(1 で初期化)

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL); // resize だとなぜか初期化されなかった
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }

  // Member Function
  // Find
  ll root(ll x) { // 根の検索
    while (par[x] != x) {
      x = par[x] = par[par[x]]; // x の親の親を x の親とする
    }
    return x;
  }

  // Union(Unite, Merge)
  bool merge(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    // merge technique（データ構造をマージするテク．小を大にくっつける）
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(ll x, ll y) { // 連結判定
    return root(x) == root(y);
  }

  ll size(ll x) { // 素集合のサイズ
    return siz[root(x)];
  }
};

// 0-indexed parmutation only
vvl cycle_partition(const vl &p) {
  ll n = p.size();
  vvl ret;
  vector<bool> check(n, false);
  rep(i, n) if (!check[p[i]]) {
    vl v;
    ll pos = p[i];
    v.pb(i);
    check[i] = true;
    while (pos != i) {
      v.pb(pos);
      check[pos] = true;
      pos = p[pos];
    }
    ret.pb(v);
  }
  return ret;
}

// Manachar　修理中
//  vl Manachar(string S){
//      ll c=0,n=S.size();
//      vl R(n,1);
//      for(ll i=0;i<n;i++){
//          ll l=c-(i-c);
//          if(i+R[l]<c+R[c]){
//              R[i]=R[l];
//          }else{
//              ll j=c+R[c]-i;
//              while(i-j>=0 && i+j<n && S[i-j] == S[i+j])j++;
//              R[i]=j;
//              c=i;
//          }
//      }
//      return R;
//  }

struct edge {
  ll to;
  ll cost;
};

ll Solve(ll n, vl a, vl b) {
  ll zerozero = 0;
  ll x = 0;
  ll y = 0;
  map<P, ll> Mplus;
  map<P, ll> Mminus;
  rep(i, n) {
    if (a[i] == 0 and b[i] == 0)
      zerozero++;
    else if (a[i] == 0 and b[i] != 0)
      x++;
    else if (a[i] != 0 and b[i] == 0)
      y++;
    else {
      if ((a[i] > 0 and b[i] > 0) or (a[i] < 0 and b[i] < 0)) {
        a[i] = abs(a[i]);
        b[i] = abs(b[i]);
        ll g = __gcd(a[i], b[i]);
        a[i] /= g;
        b[i] /= g;
        Mplus[make_pair(a[i], b[i])]++;
      } else {
        a[i] = abs(a[i]);
        b[i] = abs(b[i]);
        ll g = __gcd(a[i], b[i]);
        a[i] /= g;
        b[i] /= g;
        Mminus[make_pair(b[i], a[i])]++;
      }
    }
  }
  ll ans = 1;
  for (auto p : Mplus) {
    ans *= ((modpow(2, p.SE) + modpow(2, Mminus[p.FI])) % MOD + MOD - 1) % MOD;
    ans %= MOD;
    // if(((modpow(2,p.SE)+modpow(2,Mminus[p.FI]))%MOD+MOD-1)%MOD==0)cout<<p.SE<<"
    // "<<Mminus[p.FI]<<endl;
    Mplus[p.FI] = 0;
    Mminus[p.FI] = 0;
  }
  for (auto p : Mminus) {
    ans *= ((modpow(2, p.SE) + modpow(2, Mplus[p.FI])) % MOD + MOD - 1) % MOD;
    ans %= MOD;
    Mplus[p.FI] = 0;
    Mminus[p.FI] = 0;
  }
  // cout<<ans<<endl;
  ans *= ((modpow(2, x) + modpow(2, y)) % MOD + MOD - 1) % MOD;
  ans %= MOD;
  ans += zerozero;
  ans %= MOD;
  ans += MOD - 1;
  ans %= MOD;
  return ans;
}

ll Solve2(ll n, vl a, vl b) {
  ll cnt = 0;
  rep(bit, 1 << n) {
    if (bit == 0)
      continue;
    bool ng = false;
    rep(i, n - 1) {
      for (ll j = i + 1; j < n; j++) {
        if ((bit(bit, i)) and (bit(bit, j))) {
          if (a[i] * a[j] + b[i] * b[j] == 0)
            ng = true;
        }
      }
    }
    if (!ng)
      cnt++;
  }
  return cnt;
}

void Test() {
  random_device seed_gen;
  mt19937_64 rnd(seed_gen());

  uniform_int_distribution<ll> dist_N(100000, 100000), dist_A(-1000, 1000),
      dist_B(-1000, 1000);
  ll N = dist_N(rnd);
  vector<ll> A(N), B(N);
  for (ll i = 0; i < N; i++)
    A[i] = dist_A(rnd);
  for (ll i = 0; i < N; i++)
    B[i] = dist_B(rnd);
  // if(Solve(N,A,B)!=Solve2(N,A,B)){
  //     cout<<N<<endl;
  //     rep(i,N)cout<<A[i]<<" \\n"[i+1==N];
  //     rep(i,N)cout<<B[i]<<" \\n"[i+1==N];
  // }
  cout << Solve(N, A, B) << endl;
}

int main() {
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  cout << fixed << setprecision(10);
  /*--------------------------------*/

  ll n;
  cin >> n;
  vl a(n), b(n);
  rep(i, n) cin >> a[i] >> b[i];
  cout << Solve(n, a, b) << endl;
}

Error: 0

Fixed submission:

// #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
#define PI 3.14159265359
using namespace std;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define bit(n, k) (((ll)n >> (ll)k) & 1) /*nのk bit目*/
const long long INF = 1e+18 + 1;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vector<ll>> vvl;
typedef pair<ll, ll> P;
typedef tuple<ll, ll, ll> T;
const ll MOD = 1000000007LL;
// const ll MOD=998244353LL;
// const ll MAX_V=114514LL;
string abc = "abcdefghijklmnopqrstuvwxyz";
string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
vl dx = {-1, -1, -1, 0, 0, 1, 1, 1};
vl dy = {1, -1, 0, 1, -1, 1, 0, -1};
ll modpow(ll a, ll n, ll mod) {

  ll res = 1;
  while (n > 0) {
    if (n & 1)
      res = res * a % mod;
    a = a * a % mod;
    n >>= 1;
  }
  return res;
}
int main() {
  ll n;
  cin >> n;
  vl a(n), b(n);
  vl hugou(n);
  rep(i, n) cin >> a[i] >> b[i];
  map<pair<ll, P>, ll> M;
  rep(i, n) {
    ll g = __gcd(a[i], b[i]);
    if (g != 0)
      a[i] /= g;
    b[i] /= g;
    if ((a[i] > 0 && b[i] > 0) || (a[i] < 0 && b[i] < 0))
      hugou[i] = 1;
    else if (a[i] == 0 || b[i] == 0)
      hugou[i] = 0;
    else
      hugou[i] = -1;
    a[i] = abs(a[i]);
    b[i] = abs(b[i]);
    pair<ll, P> p;
    p.first = hugou[i];
    p.second.first = a[i];
    p.second.second = b[i];
    M[p]++;
  }
  ll ans = 1;
  for (auto bigp : M) {
    ll part = 1;
    pair<ll, P> p = bigp.first;
    // cout<<p.first<<" "<<p.second.first<<" "<<p.second.second<<"
    // "<<bigp.second<<endl;
    pair<ll, P> con;
    con.first = -1;
    con.second.first = p.second.second;
    con.second.second = p.second.first;
    if (p.first == 1 && M[con] > 0)
      continue;
    part *= modpow(2, bigp.second, MOD);
    if (bigp.first.first == -1) {
      ll part2 = 1;
      pair<ll, P> rev;
      rev.first = 1;
      rev.second.first = p.second.second;
      rev.second.second = p.second.first;
      part2 *= modpow(2, M[rev], MOD);
      part += part2;
      part += MOD;
      part--;
      part %= MOD;
    }
    ans *= part;
    ans %= MOD;
  }
  ans += MOD;
  ans--;
  ans %= MOD;
  cout << ans << endl;
}