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 Haskell (GHC 8.8.3) (judge verdict: Wrong Answer)

{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE BangPatterns, BinaryLiterals, CPP, DerivingStrategies  #-}
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances       #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, KindSignatures, LambdaCase #-}
{-# LANGUAGE MagicHash, MultiParamTypeClasses, MultiWayIf           #-}
{-# LANGUAGE NumericUnderscores, OverloadedStrings, PatternSynonyms #-}
{-# LANGUAGE RankNTypes, RecordWildCards, ScopedTypeVariables       #-}
{-# LANGUAGE StandaloneDeriving, TupleSections, TypeApplications    #-}
{-# LANGUAGE TypeFamilies, TypeInType, UnboxedTuples, ViewPatterns  #-}

import           Control.Applicative
import           Control.Exception
import           Control.Monad
import           Control.Monad.Primitive
import           Control.Monad.Reader
import           Control.Monad.ST
import           Control.Monad.State.Strict
import           Data.Bifunctor
import           Data.Bool
import qualified Data.ByteString               as B
import qualified Data.ByteString.Builder       as B
import qualified Data.ByteString.Char8         as C
import qualified Data.ByteString.Internal      as B
import qualified Data.ByteString.Unsafe        as B
import           Data.Char
import qualified Data.Foldable                 as F
import           Data.Function
import           Data.Functor.Identity
import qualified Data.IntMap.Strict            as IM
import qualified Data.IntSet                   as IS
import qualified Data.List                     as L
import qualified Data.Map.Strict               as M
import           Data.Monoid
import           Data.Ord
import           Data.Primitive
import           Data.Ratio
import           Data.Semigroup
import qualified Data.Set                      as S
import           Data.Tuple
import qualified Data.Vector                   as V
import qualified Data.Vector.Generic           as G
import qualified Data.Vector.Generic.Mutable   as GM
import qualified Data.Vector.Mutable           as VM
import qualified Data.Vector.Primitive         as P
import qualified Data.Vector.Primitive.Mutable as PM
import qualified Data.Vector.Unboxed           as U
import qualified Data.Vector.Unboxed.Mutable   as UM
import           Debug.Trace
import           Foreign                       hiding (void)
import           GHC.Exts
import qualified System.IO                     as IO
import           Unsafe.Coerce

main :: IO ()
main = do
    n <- readLn @Int
    xys <- U.unfoldr (runParser $ (,) <$> int <*> int) <$> C.getContents
    print $ solve n xys

#define MOD 1000000007

normalize :: (Int, Int) -> (Int, Int)
normalize (x, y)
    | x < 0 = (-quot x g, -quot y g)
    | otherwise = (quot x g, quot y g)
  where
    !g = gcd x y

orthogonal :: (Int, Int) -> (Int, Int)
orthogonal (x, y)
    | y < 0 = (-y, x)
    | otherwise = (y, -x)

solve :: Int -> U.Vector (Int, Int) -> IntMod
solve 1 _ = IntMod 1
solve _ (U.filter (/= (0,0)) -> xys)
    = go 1 dict
  where
    emptyCase = IntMod 1
    !onXaxis = U.length $ U.filter ((==0).snd) xys
    !onYaxis = U.length $ U.filter ((==0).fst) xys
    !onAxis = calc onXaxis onYaxis

    normalized = U.map normalize xys

    dict :: MultiSet (Int, Int)
    !dict = L.foldl' (flip insertMS) emptyMS $ U.toList normalized

    go !acc !ms
        | nullMS ms = if onAxis > 0 then onAxis * acc - 1 else acc - 1
        | !v <- findMinMS ms
        , !cntv  <- countMS v ms
        , !cntv' <- countMS (orthogonal v) ms
        = go (acc * calc cntv cntv') (deleteAllMS (orthogonal v) $ deleteAllMS v ms)

    calc :: Int -> Int -> IntMod
    calc x y = 2 ^ x + 2 ^ y - 1


newtype MultiSet a = MultiSet { getMultiSet :: M.Map a Int }
    deriving (Eq)

instance (Show a, Ord a) => Show (MultiSet a) where
    show = show . toList

instance (Ord a) => IsList (MultiSet a) where
    type Item (MultiSet a) = a
    fromList = L.foldl' (flip insertMS) emptyMS
    toList = concatMap (\(k, x) -> replicate x k)
        . M.toList
        . (coerce :: MultiSet a -> M.Map a Int)

emptyMS :: MultiSet a
emptyMS = coerce (M.empty :: M.Map a Int)

singletonMS :: a -> MultiSet a
singletonMS x = coerce $ M.singleton x (1 :: Int)

-- | /O(min(n,W))/
insertMS :: (Ord a) => a -> MultiSet a -> MultiSet a
insertMS x = coerce . M.insertWith (+) x (1 :: Int) . coerce

-- | /O(min(n,W))/
deleteMS :: (Ord a) => a -> MultiSet a -> MultiSet a
deleteMS x = (coerce :: M.Map a Int -> MultiSet a)
    . M.update (\y -> if y > 1 then Just $! y - 1 else Nothing) x
    . coerce

-- | /O(min(n,W))/
deleteAllMS :: (Ord a) => a -> MultiSet a -> MultiSet a
deleteAllMS x = (coerce :: M.Map a Int -> MultiSet a)
    . M.delete x
    . coerce

-- | /O(min(n,W))/
memberMS :: (Ord a) => a -> MultiSet a -> Bool
memberMS x = M.member x . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(min(n,W))/
notMemberMS :: (Ord a) => a -> MultiSet a -> Bool
notMemberMS x = not . memberMS x

-- | /P(min(n, W))/
countMS :: (Ord a) => a -> MultiSet a -> Int
countMS key = M.findWithDefault 0 key . coerce

-- | /O(log n)/
lookupLTMS :: (Ord a) => a -> MultiSet a -> Maybe a
lookupLTMS x = fmap fst . M.lookupLT x
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(log n)/
lookupGTMS :: (Ord a) => a -> MultiSet a -> Maybe a
lookupGTMS x = fmap fst . M.lookupGT x
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(log n)/
lookupLEMS :: (Ord a) => a -> MultiSet a -> Maybe a
lookupLEMS x = fmap fst . M.lookupLE x
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(log n)/
lookupGEMS :: (Ord a) => a -> MultiSet a -> Maybe a
lookupGEMS x = fmap fst . M.lookupGE x
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(1)/
nullMS :: MultiSet a -> Bool
nullMS = M.null
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(n)/
sizeMS :: MultiSet a -> Int
sizeMS = M.foldl' (+) 0
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(min(n,W))/
findMinMS :: (Ord a) => MultiSet a -> a
findMinMS = fst
    . M.findMin
    . (coerce :: MultiSet a -> M.Map a Int)
-- | /O(min(n,W))/
findMaxMS :: (Ord a) => MultiSet a -> a
findMaxMS = fst
    . M.findMax
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(min(n,W))/
deleteMinMS :: (Ord a) => MultiSet a -> MultiSet a
deleteMinMS = coerce
    . M.updateMin (\x -> if x > 1 then Just $! x - 1 else Nothing)
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(min(n,W))/
deleteMaxMS :: (Ord a) => MultiSet a -> MultiSet a
deleteMaxMS = coerce
    . M.updateMax (\x -> if x > 1 then Just $! x - 1 else Nothing)
    . (coerce :: MultiSet a -> M.Map a Int)

-- | /O(min(n,W))/
maxViewMS :: (Ord a) => MultiSet a -> Maybe (a, MultiSet a)
maxViewMS = maybe Nothing just
    . M.maxViewWithKey
    . (coerce :: MultiSet a -> M.Map a Int)
  where
    just ((k, x), m)
        | x > 1 = case M.insert k (x - 1) m of
            m' -> Just (k, coerce m')
        | otherwise = Just (k, coerce m)

-- | /O(min(n,W))/
minViewMS :: (Ord a) => MultiSet a -> Maybe (a, MultiSet a)
minViewMS = maybe Nothing just
    . M.minViewWithKey
    . (coerce :: MultiSet a -> M.Map a Int)
  where
    just ((k, x), m)
        | x > 1 = case M.insert k (x - 1) m of
            m' -> Just (k, coerce m')
        | otherwise = Just (k, coerce m)


-------------------------------------------------------------------------------
-- Utils
-------------------------------------------------------------------------------
rep :: Monad m => Int -> (Int -> m ()) -> m ()
rep !n = U.forM_ $ U.generate n id
{-# INLINE rep #-}
rev :: Monad m => Int -> (Int -> m ()) -> m ()
rev !n = U.forM_ $ U.iterateN n (subtract 1) (n - 1)
{-# INLINE rev #-}
infixl 8 `shiftRL`, `unsafeShiftRL`
shiftRL = unsafeShiftRL
{-# INLINE shiftRL #-}
unsafeShiftRL (I# x#) (I# i#) = I# (uncheckedIShiftRL# x# i#)
{-# INLINE unsafeShiftRL #-}
type Parser a = StateT C.ByteString Maybe a
runParser :: Parser a -> C.ByteString -> Maybe (a, C.ByteString)
runParser = runStateT
{-# INLINE runParser #-}
int :: Parser Int
int = coerce $ C.readInt . C.dropWhile isSpace
{-# INLINE int #-}
int1 :: Parser Int
int1 = fmap (subtract 1) int
{-# INLINE int1 #-}
char :: Parser Char
char = coerce C.uncons
{-# INLINE char #-}
byte :: Parser Word8
byte = coerce B.uncons
{-# INLINE byte #-}

-------------------------------------------------------------------------------
-- Data.IntMod
-------------------------------------------------------------------------------
modulus :: (Num a) => a
modulus = MOD
{-# INLINE modulus #-}
infixr 8 ^%
infixl 7 *%, /%
infixl 6 +%, -%
(+%) :: Int -> Int -> Int
(I# x#) +% (I# y#) = case x# +# y# of { r# -> I# (r# -# ((r# >=# MOD#) *# MOD#))}
{-# INLINE (+%) #-}
(-%) :: Int -> Int -> Int
(I# x#) -% (I# y#) = case x# -# y# of { r# -> I# (r# +# ((r# <# 0#) *# MOD#))}
{-# INLINE (-%) #-}
(*%) :: Int -> Int -> Int
(I# x#) *% (I# y#) = I# ((x# *# y#) `remInt#` MOD#)
{-# INLINE (*%) #-}
(/%) :: Int -> Int -> Int
(I# x#) /% (I# y#) = go# y# MOD# 1# 0# where { go# a# b# u# v# | isTrue# (b# ># 0#) = case a# `quotInt#` b# of { q# -> go# b# (a# -# (q# *# b#)) v# (u# -# (q# *# v#))} | otherwise = I# ((x# *# (u# +# MOD#)) `remInt#` MOD#)}
{-# INLINE (/%) #-}
(^%) :: Int -> Int -> Int
x ^% n | n > 0 = go 1 x n | n == 0 = 1 | otherwise = go 1 (1 /% x) (-n) where { go !acc !y !m | m .&. 1 == 0 = go acc (y *% y) (unsafeShiftR m 1) | m == 1 = acc *% y | otherwise = go (acc *% y) (y *% y) (unsafeShiftR (m - 1) 1)}
newtype IntMod = IntMod{getIntMod :: Int} deriving newtype (Eq, Ord, Read, Show, Real, Prim)
intMod :: (Integral a) => a -> IntMod
intMod x = fromIntegral $ mod (fromIntegral x) MOD
{-# INLINE intMod #-}
intModValidate :: IntMod -> Bool
intModValidate (IntMod x) = 0 <= x && x < MOD
{-# INLINE intModValidate #-}
instance Bounded IntMod where { minBound = IntMod 0; maxBound = IntMod $ modulus - 1}
instance Enum IntMod where { toEnum = intMod; fromEnum = coerce}
instance Integral IntMod where { quotRem x y = (x / y, x - x / y * y); toInteger = coerce (toInteger @Int)}
instance Num IntMod where { (+) = coerce (+%); (-) = coerce (-%); (*) = coerce (*%); abs = id; signum = const (IntMod 1); fromInteger x = coerce @Int @IntMod . fromInteger $ mod x modulus}
instance Fractional IntMod where { (/) = coerce (/%); fromRational q = fromInteger (numerator q) / fromInteger (denominator q)}
newtype instance  UM.MVector s IntMod = MV_IntMod (UM.MVector s Int)
newtype instance  U.Vector IntMod = V_IntMod (U.Vector Int)
instance U.Unbox IntMod
instance GM.MVector UM.MVector IntMod where { basicLength (MV_IntMod v) = GM.basicLength v; {-# INLINE basicLength #-}; basicUnsafeSlice i n (MV_IntMod v) = MV_IntMod $ GM.basicUnsafeSlice i n v; {-# INLINE basicUnsafeSlice #-}; basicOverlaps (MV_IntMod v1) (MV_IntMod v2) = GM.basicOverlaps v1 v2; {-# INLINE basicOverlaps #-}; basicUnsafeNew n = MV_IntMod `liftM` GM.basicUnsafeNew n; {-# INLINE basicUnsafeNew #-}; basicInitialize (MV_IntMod v) = GM.basicInitialize v; {-# INLINE basicInitialize #-}; basicUnsafeReplicate n x = MV_IntMod `liftM` GM.basicUnsafeReplicate n (coerce x); {-# INLINE basicUnsafeReplicate #-}; basicUnsafeRead (MV_IntMod v) i = coerce `liftM` GM.basicUnsafeRead v i; {-# INLINE basicUnsafeRead #-}; basicUnsafeWrite (MV_IntMod v) i x = GM.basicUnsafeWrite v i (coerce x); {-# INLINE basicUnsafeWrite #-}; basicClear (MV_IntMod v) = GM.basicClear v; {-# INLINE basicClear #-}; basicSet (MV_IntMod v) x = GM.basicSet v (coerce x); {-# INLINE basicSet #-}; basicUnsafeCopy (MV_IntMod v1) (MV_IntMod v2) = GM.basicUnsafeCopy v1 v2; {-# INLINE basicUnsafeCopy #-}; basicUnsafeMove (MV_IntMod v1) (MV_IntMod v2) = GM.basicUnsafeMove v1 v2; {-# INLINE basicUnsafeMove #-}; basicUnsafeGrow (MV_IntMod v) n = MV_IntMod `liftM` GM.basicUnsafeGrow v n; {-# INLINE basicUnsafeGrow #-}}
instance G.Vector U.Vector IntMod where { basicUnsafeFreeze (MV_IntMod v) = V_IntMod `liftM` G.basicUnsafeFreeze v; {-# INLINE basicUnsafeFreeze #-}; basicUnsafeThaw (V_IntMod v) = MV_IntMod `liftM` G.basicUnsafeThaw v; {-# INLINE basicUnsafeThaw #-}; basicLength (V_IntMod v) = G.basicLength v; {-# INLINE basicLength #-}; basicUnsafeSlice i n (V_IntMod v) = V_IntMod $ G.basicUnsafeSlice i n v; {-# INLINE basicUnsafeSlice #-}; basicUnsafeIndexM (V_IntMod v) i = coerce `liftM` G.basicUnsafeIndexM v i; {-# INLINE basicUnsafeIndexM #-}; basicUnsafeCopy (MV_IntMod mv) (V_IntMod v) = G.basicUnsafeCopy mv v; elemseq _ = seq; {-# INLINE elemseq #-}}