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# (Mono-csc 3.5.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Numerics;
using System.Threading;
using static System.Math;
using static System.Array;
using static AtCoder.IO_ShortCut;
using static AtCoder.Tool;
using static AtCoder.ModInt;
namespace AtCoder
{
    class AC
    {
        const int MOD = 1000000007;
        //const int MOD = 998244353;
        const int INF = int.MaxValue / 2;
        const long SINF = long.MaxValue / 2;
        const double EPS = 1e-8;
        static readonly int[] dI = { 0, 1, 0, -1, 1, -1, -1, 1 };
        static readonly int[] dJ = { 1, 0, -1, 0, 1, 1, -1, -1 };
        static List<List<int>> G = new List<List<int>>();
        //static List<List<Edge>> G = new List<List<Edge>>();
        static List<Edge> E = new List<Edge>();
        static void Main(string[] args)
        {
            //var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(sw);

            /*var th = new Thread(Run, 1 << 26);
            th.Start();
            th.Join();*/

            Run();
            Console.Out.Flush();
        }

        static void Run()
        {
            int Testcase = 1;
            for (var _ = 0; _ < Testcase; _++) Solve();
        }
        static void Solve()
        {
            int N = Int;
            if (N == 1)
            {
                OutL(1);
                return;
            }
            var A = new long[N];
            var B = new long[N];
            long Gcd(long x, long y)
            {
                if (x == 0 || y == 0) return Max(x, y);
                else return x % y == 0 ? y : Gcd(y, x % y);
            }
            var rec = new Dictionary<Tuple<long, long>, long>();
            var used = new Dictionary<Tuple<long, long>, bool>();
            ModInt ans = 0;
            long zero = 0;
            long azero = 0;
            long bzero = 0;
            for(var i = 0; i < N; i++)
            {
                Input(out A[i], out B[i]);
                if (A[i] == 0 || B[i] == 0)
                {
                    if (A[i] == 0 && B[i] == 0) zero++;
                    else if (A[i] == 0) azero++;
                    else bzero++;
                    continue;
                }
                var g = Gcd(Abs(A[i]), Abs(B[i]));
                if (A[i] < 0) { A[i] = -A[i];B[i] = -B[i]; }
                var t = new Tuple<long, long>(A[i] / g, B[i] / g);

                //OutL(t);
                if (rec.ContainsKey(t)) rec[t]++;
                else rec[t] = 1;

                if (!used.ContainsKey(t)) used[t] = false;
            }
            ans = 1;
            var md = new Modulo(1, MOD);

            foreach(var ts in rec)
            {
                //Out_One(ts.Key);
                if (used[ts.Key]) continue;
                long a = ts.Key.Item1;
                long b = ts.Key.Item2;
                long x = ts.Value;

                var p = b < 0 ? new Tuple<long, long>(Abs(b), Abs(a)) : new Tuple<long, long>(Abs(b), -Abs(a));
                //OutL(p);
                if (rec.ContainsKey(p) && !used[p])
                {
                    used[p] = true;
                    used[ts.Key] = true;
                    ans *= ((md.Pow(2, x) + md.Pow(2, rec[p]) - 1 + MOD) % MOD);
                    /*OutL("pexist.");
                    Out_Sep(x, rec[p]);*/
                }
                else
                {
                    used[ts.Key] = true;
                    ans *= md.Pow(2, x);
                    /*OutL("not.");
                    OutL(x);*/
                }
            }
            ans *= (Modpow(2, azero) + Modpow(2, bzero) - 1);
            ans--;
            ans += zero;

            OutL(ans.value);


        }
        

        public struct Edge
        {
            public int from;

            public int to;
            public long dist;

            public Edge(int t, long c)
            {
                from = -1;
                to = t;
                dist = c;
            }
            public Edge(int f, int t, long c)
            {
                from = f;
                to = t;
                dist = c;
            }
        }
        

    }
    
    struct ModInt
    {
        public long value;
        private const int MOD = 1000000007;
        //private const int MOD = 998244353;

        public ModInt(long value) { this.value = value; }
        public static implicit operator ModInt(long a)
        {
            var ret = a % MOD;
            return new ModInt(ret < 0 ? (ret + MOD) : ret);
        }
        public static ModInt operator +(ModInt a, ModInt b) => (a.value + b.value);
        public static ModInt operator -(ModInt a, ModInt b) => (a.value - b.value);
        public static ModInt operator *(ModInt a, ModInt b) => (a.value * b.value);
        public static ModInt operator /(ModInt a, ModInt b) => a * Modpow(b, MOD - 2);
        public static ModInt operator <<(ModInt a, int n) => (a.value << n);
        public static ModInt operator >>(ModInt a, int n) => (a.value >> n);
        public static ModInt operator ++(ModInt a) => a.value + 1;
        public static ModInt operator --(ModInt a) => a.value - 1;
        public static ModInt Modpow(ModInt a, long n)
        {
            var k = a;
            ModInt ret = 1;
            while (n > 0)
            {
                if ((n & 1) != 0) ret *= k;
                k *= k;
                n >>= 1;
            }
            return ret;
        }
        private static readonly List<long> Factorials = new List<long>() { 1 };
        public static ModInt Fac(long n)
        {
            for (var i = Factorials.Count(); i <= n; i++)
            {
                Factorials.Add((Factorials[i - 1] * i) % MOD);
            }
            return Factorials[(int)n];
        }
        public static ModInt nCr(long n, long r)
        {
            return n < r ? 0 : Fac(n) / (Fac(r) * Fac(n - r));
        }
        public static explicit operator int(ModInt a) => (int)a.value;
    }
    static class IO_ShortCut
    {
        public static string[] _ReadSplit => Console.ReadLine().Split();
        public static int[] _ReadSplitInt => ConvertAll(Console.ReadLine().Split(), int.Parse);
        public static long[] _ReadSplitLong => ConvertAll(Console.ReadLine().Split(), long.Parse);
        public static double[] _ReadSplit_Double => ConvertAll(Console.ReadLine().Split(), double.Parse);
        public static string Str => Console.ReadLine();
        public static int Int => int.Parse(Console.ReadLine());
        public static long Long => long.Parse(Console.ReadLine());
        public static double Double => double.Parse(Console.ReadLine());
        public static T Conv<T>(string input)
        {
            if (typeof(T).Equals(typeof(ModInt)))
            {
                return (T)(dynamic)(long.Parse(input));
            }
            return (T)Convert.ChangeType(input, typeof(T));
        }
        public static void Input<T>(out T a) => a = Conv<T>(Console.ReadLine());
        public static void Input<T, U>(out T a, out U b)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); }
        public static void Input<T, U, V>(out T a, out U b, out V c)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); }
        public static void Input<T, U, V, W>(out T a, out U b, out V c, out W d)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); }
        public static void Input<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); e = Conv<X>(q[4]); }

        public static void OutL(object s) => Console.WriteLine(s);
        public static void Out_Sep<T>(IEnumerable<T> s) => Console.WriteLine(string.Join(" ", s));
        public static void Out_Sep<T>(IEnumerable<T> s, string sep) => Console.WriteLine(string.Join($"{sep}", s));
        public static void Out_Sep(params object[] s) => Console.WriteLine(string.Join(" ", s));
        public static void Out_One(object s) => Console.Write($"{s} ");
        public static void Out_One(object s, string sep) => Console.Write($"{s}{sep}");
        public static void Endl() => Console.WriteLine();
    }
    public static class Tool
    {
        static public void Initialize<T>(ref T[] array, T initialvalue)
        {
            array = ConvertAll(array, x => initialvalue);
        }
        static public void Swap<T>(ref T a, ref T b)
        {
            T keep = a;
            a = b;
            b = keep;
        }
        static public void Display<T>(T[,] array2d, int n, int m)
        {
            for (var i = 0; i < n; i++)
            {
                for (var j = 0; j < m; j++)
                {
                    Console.Write($"{array2d[i, j]} ");
                }
                Console.WriteLine();
            }
        }
        static public long Gcd(long a, long b)
        {
            if (a == 0 || b == 0) return Max(a, b);
            return a % b == 0 ? b : Gcd(b, a % b);
        }
        static public long LPow(int a, int b) => (long)Pow(a, b);
        static public bool Bit(long x, int dig) => ((1L << dig) & x) != 0;
        static public int Sig(long a) => a == 0 ? 0 : (int)(a / Abs(a));
    }
    class Modulo
    {
        private int M;
        private readonly long[] m_facs;
        public long Mul(long a, long b)
        {
            return ((a * b) % M);
        }
        public Modulo(long n, int m)
        {
            M = m;
            m_facs = new long[n + 1];
            m_facs[0] = 1;
            for (long i = 1; i <= n; ++i)
            {
                m_facs[i] = Mul(m_facs[i - 1], i);
            }
        }
        public long Fac(long n)
        {
            return m_facs[n];
        }
        public long Pow(long a, long m)
        {
            switch (m)
            {
                case 0:
                    return 1L;
                case 1:
                    return a;
                default:
                    long p1 = Pow(a, m / 2);
                    long p2 = Mul(p1, p1);
                    return ((m % 2) == 0) ? p2 : Mul(p2, a);
            }
        }
        public long Div(long a, long b)
        {
            return Mul(a, Pow(b, M - 2));
        }
        public long Ncr(long n, long r)
        {
            if (n < r) { return 0; }
            if (n == r) { return 1; }
            long res = Fac(n);
            res = Div(res, Fac(r));
            res = Div(res, Fac(n - r));
            return res;
        }
    }
}