Problem p02679 (C++) — buggy submission, verdict: Time Limit Exceeded

// #include <cstdio>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
// #include <queue>
// #include <stack>
#include <cassert>
#include <cstring>

using namespace std;

#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(x...)                                                            \\
  cerr << __LINE__ << ": " << #x << " = ";                                     \\
  DBG::_print(x)
#else
#define DEBUG(x...)
#endif

#define SZ(a) int((a).size())
#define REP(i, n) for (int i = 0, _n = (n); i < _n; ++i)
#define FOR(i, a, b) for (int i = (a), _b = (b); i <= _b; ++i)

typedef long long llong;
typedef vector<int> VI;
typedef vector<VI> VVI;

llong gcd(llong a, llong b) {
  if (a < 0)
    a = -a;
  if (b < 0)
    b = -b;
  if (a < b)
    swap(a, b);
  while (b > 0) {
    llong t = b;
    b = a % b;
    a = t;
  }
  return a > 0 ? a : 1;
}

long long powmod(long long x, long long n, unsigned int m) {
  long long res = 1 % m;
  x %= m;
  for (; n > 0; n >>= 1) {
    if (n & 1) {
      res = (res * x) % m;
      // n--;
    }
    x = (x * x) % m;
  }
  return res;
}

const size_t SEED =
    chrono::high_resolution_clock::now().time_since_epoch().count();

struct Fraction {
  llong num, den;
  Fraction(llong n, llong d) {
    llong g = gcd(n, d);
    num = n / g;
    den = d / g;
    if (den < 0) {
      num = -num;
      den = -den;
    }
    if (den == 0)
      num = 1;
  }
  bool operator==(const Fraction &f) const {
    return num == f.num && den == f.den;
  }
  string to_string() const {
    return std::to_string(num) + "/" + std::to_string(den);
  }
};

struct FractionHash {
  size_t operator()(const Fraction &f) const {
    size_t res = hash<long long>{}(f.num ^ (f.den << 2));
    return hash<int>{}(res ^ SEED);
  }
};

const int MOD = 1e9 + 7;

int solve(int N, const vector<llong> &A, const vector<llong> &B) {
  int cnt_zeros = 0;
  unordered_map<Fraction, int, FractionHash> freq;
  REP(i, N) {
    llong x = A[i], y = B[i];
    if (x == 0 && y == 0)
      ++cnt_zeros;
    else
      ++freq[Fraction(x, y)];
  }

  if (cnt_zeros == N)
    return N;

  llong res = 1;
  while (!freq.empty()) {
    auto it1 = freq.begin();
    Fraction f = it1->first;
    int cnt1 = it1->second;
    freq.erase(it1);

    llong factor = 0;

    // try to match forbidden pairs of sardines
    Fraction invf(-f.den, f.num);
    auto it2 = freq.find(invf);
    if (it2 != freq.end()) {
      int cnt2 = it2->second;
      freq.erase(it2);
      factor = powmod(2, cnt1, MOD) -
               1 // select non-empty subset of first set of sardines
               + powmod(2, cnt2, MOD) -
               1    // select non-empty subset of second set of sardines
               + 1; // select none of sardines
      if (factor >= MOD)
        factor -= MOD;
    } else
      factor = powmod(2, cnt1, MOD); // select a subset of these sardines

    res = (res * factor) % MOD;
  }

  res += cnt_zeros;
  if (res >= MOD)
    res -= MOD;

  res--;
  if (res < 0)
    res += MOD;

  return res;
}

int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  int N;
  cin >> N;
  vector<llong> A(N), B(N);
  REP(i, N)
  cin >> A[i] >> B[i];

  int res = solve(N, A, B);
  cout << res << '\\n';

  return 0;
}


Error: TLE

Fixed submission:

// #include <cstdio>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
// #include <queue>
// #include <stack>
#include <cassert>
#include <cstring>

using namespace std;

#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(x...)                                                            \\
  cerr << __LINE__ << ": " << #x << " = ";                                     \\
  DBG::_print(x)
#else
#define DEBUG(x...)
#endif

#define SZ(a) int((a).size())
#define REP(i, n) for (int i = 0, _n = (n); i < _n; ++i)
#define FOR(i, a, b) for (int i = (a), _b = (b); i <= _b; ++i)

typedef long long llong;
typedef vector<int> VI;
typedef vector<VI> VVI;

llong gcd(llong a, llong b) {
  if (a < 0)
    a = -a;
  if (b < 0)
    b = -b;
  if (a < b)
    swap(a, b);
  while (b > 0) {
    llong t = b;
    b = a % b;
    a = t;
  }
  return a > 0 ? a : 1;
}

long long powmod(long long x, long long n, unsigned int m) {
  long long res = 1 % m;
  x %= m;
  for (; n > 0; n >>= 1) {
    if (n & 1) {
      res = (res * x) % m;
      // n--;
    }
    x = (x * x) % m;
  }
  return res;
}

const size_t SEED =
    chrono::high_resolution_clock::now().time_since_epoch().count();

struct Fraction {
  llong num, den;
  Fraction(llong n, llong d) {
    llong g = gcd(n, d);
    num = n / g;
    den = d / g;
    if (den < 0) {
      num = -num;
      den = -den;
    }
    if (den == 0)
      num = 1;
  }
  bool operator==(const Fraction &f) const {
    return num == f.num && den == f.den;
  }
  string to_string() const {
    return std::to_string(num) + "/" + std::to_string(den);
  }
};

struct FractionHash {
  size_t operator()(const Fraction &f) const {
    size_t res = hash<long long>{}(f.num ^ (f.den << 1));
    return hash<int>{}(res ^ SEED);
  }
};

const int MOD = 1e9 + 7;

int solve(int N, const vector<llong> &A, const vector<llong> &B) {
  int cnt_zeros = 0;
  unordered_map<Fraction, int, FractionHash> freq;
  REP(i, N) {
    llong x = A[i], y = B[i];
    if (x == 0 && y == 0)
      ++cnt_zeros;
    else
      ++freq[Fraction(x, y)];
  }

  if (cnt_zeros == N)
    return N;

  llong res = 1;
  while (!freq.empty()) {
    auto it1 = freq.begin();
    Fraction f = it1->first;
    int cnt1 = it1->second;
    freq.erase(it1);

    llong factor = 0;

    // try to match forbidden pairs of sardines
    Fraction invf(-f.den, f.num);
    auto it2 = freq.find(invf);
    if (it2 != freq.end()) {
      int cnt2 = it2->second;
      freq.erase(it2);
      factor = powmod(2, cnt1, MOD) -
               1 + // select non-empty subset of first set of sardines
               powmod(2, cnt2, MOD) -
               1 + // select non-empty subset of second set of sardines
               1;  // select none of sardines
      factor %= MOD;
    } else
      factor = powmod(2, cnt1, MOD); // select a subset of these sardines

    res = (res * factor) % MOD;
  }

  res += cnt_zeros;
  if (res >= MOD)
    res -= MOD;

  res--;
  if (res < 0)
    res += MOD;

  return res;
}

int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  int N;
  cin >> N;
  vector<llong> A(N), B(N);
  REP(i, N)
  cin >> A[i] >> B[i];

  int res = solve(N, A, B);
  cout << res << '\\n';

  return 0;
}