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

/*
AB=0,0はコーナーケースこれらを足した上で,
省いて普通の分析につなげる

S, Tに対して, それぞれの集合は直線上で
sとtは直行

この時, SかTかのどっちかのみ選べる
選び方は2^|S|+2^|T|-1(空集合に注意)
これをS[i]で掛け合わせればいい

問題はS[i]の分類, どうやって同じ直線上の点を検出するか
角度に直して分析? doubleだと誤差がだるそう
最大公約数で割り算? logAなのでいけそう

*/

#include <bits/stdc++.h>
using namespace std;
typedef pair<long, long> P;
#define Q 1000000007
long gcd(long x, long y) { return (x % y == 0 ? y : gcd(y, x % y)); }
long pow(long x) {
  if (x == 0)
    return 1;
  if (x % 2)
    return pow(x - 1) * 2 % Q;
  else {
    long y = pow(x / 2);
    return y * y % Q;
  }
}
int main() {
  long N;
  cin >> N;
  vector<P> S, T;
  long ans = 0;
  for (long i = 0; i < N; i++) {
    long a, b;
    cin >> a >> b;
    // [0,90), [90,180)にする
    if (a == 0 && b == 0) {
      ans++;
      continue;
    }
    if ((a < 0 && b <= 0) || (a >= 0 && b < 0)) {
      a *= -1;
      b *= -1;
    }
    if (a > 0 && b >= 0) { //[0,90)
      if (b == 0)
        S.push_back(P(1, 0));
      else {
        long g = gcd(a, b);
        S.push_back(P(a / g, b / g));
      }
    } else if (a <= 0 && b > 0) { //[90,180),
      // これをさらに90度回転させて[0,90)に

      if (a == 0)
        T.push_back(P(1, 0));
      else {
        long g = gcd(-a, b);
        T.push_back(P(b / g, -a / g));
      }
    } else
      cout << "error";
  }
  // map<P,P>: ベクトル/ (Sの個数,Tの個数)
  // set, 登録されたベクトル
  map<P, P> VST;
  for (P s : S) {
    VST[s].first++;
  }
  for (P t : T) {
    VST[t].second++;
  }
  long x = 1;
  for (const auto &[k, v] : VST) {
    x = x * ((pow(v.first) + pow(v.second) - 1) % Q) % Q;
  }
  assert((ans + x - 1 + Q) % Q >= 0);
  cout << (ans + x - 1 + Q) % Q;
}

Error: WA

Fixed submission:

/*
AB=0,0はコーナーケースこれらを足した上で,
省いて普通の分析につなげる

S, Tに対して, それぞれの集合は直線上で
sとtは直行

この時, SかTかのどっちかのみ選べる
選び方は2^|S|+2^|T|-1(空集合に注意)
これをS[i]で掛け合わせればいい

問題はS[i]の分類, どうやって同じ直線上の点を検出するか
角度に直して分析? doubleだと誤差がだるそう
最大公約数で割り算? logAなのでいけそう

*/

#include <bits/stdc++.h>
using namespace std;
typedef pair<long, long> P;
#define Q 1000000007
long gcd(long x, long y) { return (x % y == 0 ? y : gcd(y, x % y)); }
long pow(long x) {
  if (x == 0)
    return 1;
  if (x % 2)
    return pow(x - 1) * 2 % Q;
  else {
    long y = pow(x / 2);
    return y * y % Q;
  }
}
int main() {
  long N;
  cin >> N;
  vector<P> S, T;
  long ans = 0;
  for (long i = 0; i < N; i++) {
    long a, b;
    cin >> a >> b;
    // [0,90), [90,180)にする
    if (a == 0 && b == 0) {
      ans++;
      continue;
    }
    if ((a < 0 && b <= 0) || (a >= 0 && b < 0)) {
      a *= -1;
      b *= -1;
    }
    if (a > 0 && b >= 0) { //[0,90)
      if (b == 0)
        S.push_back(P(1, 0));
      else {
        long g = gcd(a, b);
        S.push_back(P(a / g, b / g));
      }
    } else if (a <= 0 && b > 0) { //[90,180),
      // これをさらに90度回転させて[0,90)に

      if (a == 0)
        T.push_back(P(1, 0));
      else {
        long g = gcd(-a, b);
        T.push_back(P(b / g, -a / g));
      }
    } else
      cout << "error";
  }
  // map<P,P>: ベクトル/ (Sの個数,Tの個数)
  // set, 登録されたベクトル
  map<P, P> VST;
  for (P s : S) {
    VST[s].first++;
  }
  for (P t : T) {
    VST[t].second++;
  }
  long x = 1;
  for (const auto &[k, v] : VST) {
    x = x * ((pow(v.first) + pow(v.second) - 1) % Q) % Q;
  }
  assert((ans + x - 1) % Q >= 0);
  cout << (ans + x - 1) % Q;
}