Problem:
Score : 500 points

Problem Statement

Let us denote by f(x, m) the remainder of the Euclidean division of x by m.

Let A be the sequence that is defined by the initial value A_1=X and the recurrence relation A_{n+1} = f(A_n^2, M).
Find \displaystyle{\sum_{i=1}^N A_i}.

Constraints

1 \leq N \leq 10^{10}

0 \leq X < M \leq 10^5

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N X M

Output

Print \displaystyle{\sum_{i=1}^N A_i}.

Sample Input 1

6 2 1001

Sample Output 1

1369

The sequence A begins 2,4,16,256,471,620,\ldots Therefore, the answer is 2+4+16+256+471+620=1369.

Sample Input 2

1000 2 16

Sample Output 2

6

The sequence A begins 2,4,0,0,\ldots Therefore, the answer is 6.

Sample Input 3

10000000000 10 99959

Sample Output 3

492443256176507

Solution in Haskell (GHC 8.8.3) (judge verdict: Accepted)

{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import Control.Monad
import Control.Monad.Extra
import qualified Data.Array as A
import qualified Data.Array.IO as AIO
import qualified Data.Array.Unboxed as AU
import Data.Bits
import Data.Bool
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC8
import Data.Char
import Data.Either
import Data.Function
import qualified Data.Graph.Inductive.Graph as G
import qualified Data.Graph.Inductive.PatriciaTree as G
import qualified Data.Heap as H
import Data.Int
import Data.List
import qualified Data.Map.Strict as M
import Data.Maybe
import Data.Monoid
import Data.Ord
import qualified Data.Sequence as SQ
import qualified Data.Set as S
import Data.Time
import Data.Tuple
import qualified Data.Vector as V
import Data.Vector.Algorithms.Search
import qualified Data.Vector.Mutable as VM
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import qualified Data.Vector.Unboxing as VUG
import qualified Data.Vector.Unboxing.Mutable as VUGM
import Debug.Trace
import GHC.Base
import GHC.Stack

main :: HasCallStack => IO ()
main = do
  --aN       <- getI
  --[aA, aB] <- getIL
  --aS       <- getLine
  [aN, aX, aM] <- getIL

  let shiftCnt = shiftRCnt aN
  nextTable <- VM.replicateM (shiftCnt + 1) $ VUM.replicate (aM) (-1) :: IO (VM.IOVector (VUM.IOVector (Int)))
  sumTable <- VM.replicateM (shiftCnt + 1) $ VUM.replicate (aM) (-1) :: IO (VM.IOVector (VUM.IOVector (Int)))

  nextTable0 <- VM.read nextTable 0
  sumTable0 <- VM.read sumTable 0

  {-
    VU.mapM_
      ( \v -> do
          let modv2am = mod (v ^ 2) aM
          VUM.write nextTable0 v modv2am
          VUM.write sumTable0 v v
      )
      $ VU.enumFromN 0 aM
  -}
  targetList <-
    VU.unfoldrM
      ( \x -> do
          let modxam = mod (x ^ 2) aM
          i <- VUM.read nextTable0 x
          if i == (-1)
            then do
              VUM.write nextTable0 x modxam
              VUM.write sumTable0 x x
              return $
                Just (x, modxam)
            else return Nothing
      )
      aX
  print =<< doublingTarget nextTable sumTable aN aM shiftCnt aX targetList

  return ()

doublingAll nextTable sumTable n m shiftCnt s = do
  VU.mapM_
    ( \i -> do
        nextTablei <- VM.read nextTable i
        nextTablei1 <- VM.read nextTable (i + 1)
        sumTablei <- VM.read sumTable i
        sumTablei1 <- VM.read sumTable (i + 1)
        VU.mapM_
          ( \v -> do
              nextTableiv <- VUM.read nextTablei v
              nextTableiiv <- VUM.read nextTablei nextTableiv
              VUM.write nextTablei1 v nextTableiiv
              sumTableiv <- VUM.read sumTablei v
              sumTableiiv <- VUM.read sumTablei nextTableiv
              VUM.write sumTablei1 v (sumTableiv + sumTableiiv)
          )
          $ VU.enumFromN 0 m
    )
    $ VU.enumFromN 0 $ shiftCnt
  acc@(next, sum) <-
    VU.foldM
      ( \acc@(next, sum) i -> do
          if n .&. (shiftL 1 i) /= 0
            then do
              nextTablei <- VM.read nextTable i
              nnext <- VUM.read nextTablei next

              sumTablei <- VM.read sumTable i
              sump <- VUM.read sumTablei next
              return (nnext, sum + sump)
            else return acc
      )
      (s, 0)
      $ VU.enumFromN 0 $ shiftCnt
  return sum

doublingTarget nextTable sumTable n m shiftCnt s targetList = do
  VU.mapM_
    ( \i -> do
        nextTablei <- VM.read nextTable i
        nextTablei1 <- VM.read nextTable (i + 1)
        sumTablei <- VM.read sumTable i
        sumTablei1 <- VM.read sumTable (i + 1)
        VU.mapM_
          ( \v -> do
              nextTableiv <- VUM.read nextTablei v
              nextTableiiv <- VUM.read nextTablei nextTableiv
              VUM.write nextTablei1 v nextTableiiv
              sumTableiv <- VUM.read sumTablei v
              sumTableiiv <- VUM.read sumTablei nextTableiv
              VUM.write sumTablei1 v (sumTableiv + sumTableiiv)
          )
          $ targetList
    )
    $ VU.enumFromN 0 $ shiftCnt
  acc@(next, sum) <-
    VU.foldM
      ( \acc@(next, sum) i -> do
          if n .&. (shiftL 1 i) /= 0
            then do
              nextTablei <- VM.read nextTable i
              nnext <- VUM.read nextTablei next

              sumTablei <- VM.read sumTable i
              sump <- VUM.read sumTablei next
              return (nnext, sum + sump)
            else return acc
      )
      (s, 0)
      $ VU.enumFromN 0 $ shiftCnt
  return sum

--雑多系
t :: Int -> (Int, Int)
t x = (x, 1)

i def f t = bool t def $ f t

shiftRCnt k = shiftRCntP k 1

shiftRCntP k c =
  let nk = shiftR k 1
   in if nk == 0
        then c
        else shiftRCntP nk (c + 1)

myVUmap f vu =
  if vu == VU.empty
    then VU.empty
    else
      VU.unfoldr
        ( \x ->
            let ret = f $ VU.head x
                tailx = VU.tail x
             in if x == VU.empty
                  then Nothing
                  else
                    if isLeft ret
                      then Just (either id id ret, tailx)
                      else Just (either id id ret, VU.empty)
        )
        vu

myVUmapM f vu =
  if vu == VU.empty
    then return VU.empty
    else
      VU.unfoldrM
        ( \x -> do
            ret <- f $ VU.head x
            let tailx = VU.tail x
            if x == VU.empty
              then return Nothing
              else
                if isLeft ret
                  then return $ Just (either id id ret, tailx)
                  else return $ Just (either id id ret, VU.empty)
        )
        vu

myVUmapM_ f vu =
  if vu == VU.empty
    then return ()
    else do
      ret1 <-
        VU.unfoldrM
          ( \x -> do
              ret2 <- f $ VU.head x
              let tailx = VU.tail x
              if x == VU.empty
                then return Nothing
                else
                  if isLeft ret2
                    then return $ Just (either id id ret2, tailx)
                    else return $ Just (either id id ret2, VU.empty)
          )
          vu
      return ()

myVUfor vu f = myVUmap f vu

myVUforM vu f = myVUmapM f vu

myVUforM_ vu f = myVUmapM_ f vu

myVUfoldl f acc vu =
  if vu == VU.empty
    then return acc
    else do
      let ret = f acc (VU.head vu)
      if isLeft ret
        then myVUfoldl f (either id id ret) (VU.tail vu)
        else return $ either id id ret

myVUfoldr f acc vu =
  if vu == VU.empty
    then return acc
    else do
      let ret = f acc (VU.last vu)
      if isLeft ret
        then myVUfoldr f (either id id ret) (VU.init vu)
        else return $ either id id ret

myVUfoldM f acc vu =
  if vu == VU.empty
    then return acc
    else do
      ret <- f acc (VU.head vu)
      if isLeft ret
        then myVUfoldM f (either id id ret) (VU.tail vu)
        else return $ either id id ret

--周りのマス
aroundSquare y x h w =
  VU.concatMap
    ( \a ->
        VU.mapMaybe
          ( \b ->
              let ya = y + a
                  xb = x + b
               in if abs a + abs b == 1
                    then
                      if ya < 0 || ya >= h || xb < 0 || xb >= w
                        then Nothing
                        else Just (ya, xb)
                    else Nothing
          )
          $ VU.enumFromN (-1) 3
    )
    $ VU.enumFromN (-1) 3

--入力系
splitReadBSC8 :: BSC8.ByteString -> [Int]
splitReadBSC8 bs =
  let (bs1, newBs) = BSC8.splitAt 1 bs
   in if newBs == BSC8.empty
        then [test $ BSC8.readInt bs1]
        else test (BSC8.readInt bs1) : splitReadBSC8 newBs
  where
    test (Just (i, _)) = i

read2DimChar :: VM.IOVector (VUM.IOVector Char) -> Int -> Int -> IO Char
read2DimChar vec y x = do
  vecY <- VM.read vec y
  VUM.read vecY x

write2DimChar :: VM.IOVector (VUM.IOVector Char) -> Int -> Int -> Char -> IO ()
write2DimChar vec y x t = do
  vecY <- VM.read vec y
  VUM.write vecY x t

readTwoDimVec :: VM.IOVector (VUM.IOVector Int) -> Int -> Int -> IO Int
readTwoDimVec vec y x = do
  vecY <- VM.read vec y
  VUM.read vecY x

writeTwoDimVec :: VM.IOVector (VUM.IOVector Int) -> Int -> Int -> Int -> IO ()
writeTwoDimVec vec y x t = do
  vecY <- VM.read vec y
  VUM.write vecY x t

getVUI :: IO (VU.Vector Int)
getVUI = VU.unfoldr (BSC8.readInt . BSC8.dropWhile isSpace) <$> BSC8.getLine

getRepVUI :: Int -> IO (VU.Vector Int)
getRepVUI n =
  VU.unfoldr (BSC8.readInt . BSC8.dropWhile isSpace) . BSC8.unlines
    <$> replicateM n BSC8.getLine

getVS :: IO (V.Vector Char)
getVS = V.fromList <$> getLine

getVUC :: IO (VU.Vector Char)
getVUC = VU.fromList <$> getLine

readI :: BSC8.ByteString -> Int
readI = fst . fromJust . BSC8.readInt

readInteger :: BSC8.ByteString -> Integer
readInteger = fst . fromJust . BSC8.readInteger

readIL :: BSC8.ByteString -> [Int]
readIL = map readI . BSC8.words

readIT2 :: BSC8.ByteString -> (Int, Int)
readIT2 bs =
  let words = BSC8.words bs
   in (readI $ head words, readI $ last words)

readIT3 :: BSC8.ByteString -> (Int, Int, Int)
readIT3 bs =
  let words = BSC8.words bs
   in (readI $ head words, readI $ words !! 1, readI $ words !! 2)

getI :: IO Int
getI = readI <$> BSC8.getLine

getInteger :: IO Integer
getInteger = readInteger <$> BSC8.getLine

getIL :: IO [Int]
getIL = readIL <$> BSC8.getLine

getIT2 :: IO (Int, Int)
getIT2 = readIT2 <$> BSC8.getLine

getIT3 :: IO (Int, Int, Int)
getIT3 = readIT3 <$> BSC8.getLine

getIT2Order :: IO (Int, Int)
getIT2Order =
  getIL
    >>= \x@[xz, xo] ->
      if xz > xo
        then return (xo, xz)
        else return (xz, xo)

getNIS :: Int -> IO [(Int, BSC8.ByteString)]
getNIS 0 = return []
getNIS n = do
  [aFst, aSnd] <- BSC8.words <$> BSC8.getLine
  next <- getNIS (n - 1)
  return ((readI aFst, aSnd) : next)

il2Words :: [Int] -> String
il2Words = unwords . map show

il2Lines :: [Int] -> String
il2Lines = unlines . map show