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
  loopInfo <-
    VU.unfoldrM
      ( \(x, n, k, m) ->
          if n == aN
            then return Nothing
            else do
              if n /= k
                then return Nothing
                else do
                  let modxam = mod x aM
                  let key = M.findWithDefault (-1) modxam m
                  if key == -1
                    then
                      let nm = M.insert modxam (n + 1) m
                       in return $ Just ((x, modxam, n + 1), (modxam ^ 2, n + 1, n + 1, nm))
                    else return $ Just ((x, modxam, key), (modxam ^ 2, n + 1, key, m))
      )
      (aX, 0, 0, M.empty)
  let (_, _, n) = VU.last loopInfo
  if n == aN
    then
      let (_, vunum, _) = VU.unzip3 loopInfo
       in print $ VU.sum vunum
    else do
      let (_, vunum, vunext) = VU.unzip3 loopInfo
      let shiftCnt = shiftRCnt aN
      nextTable <- VM.replicateM (shiftCnt + 1) $ VUM.replicate (VU.length loopInfo) 0 :: IO (VM.IOVector (VUM.IOVector (Int)))
      numTable <- VM.replicateM (shiftCnt + 1) $ VUM.replicate (VU.length loopInfo) 0 :: IO (VM.IOVector (VUM.IOVector (Int)))
      VU.mapM_
        ( \i -> do
            nextTable0 <- VM.read nextTable 0
            numTable0 <- VM.read numTable 0
            aa <-
              if i > 1
                then VUM.read numTable0 (i -1)
                else return 0
            VUM.write nextTable0 i (vunext VU.! i)
            VUM.write numTable0 i (vunum VU.! i)
        )
        $ VU.enumFromN 0 $ VU.length loopInfo
      VU.mapM_
        ( \i -> do
            nextTablei <- VM.read nextTable i
            nextTablei1 <- VM.read nextTable (i + 1)
            numTablei <- VM.read numTable i
            numTablei1 <- VM.read numTable (i + 1)
            VU.mapM_
              ( \v -> do
                  nextTableiv <- VUM.read nextTablei v
                  nextTableiiv <- VUM.read nextTablei nextTableiv

                  VUM.write nextTablei1 v nextTableiiv
                  numTableiv <- VUM.read numTablei v
                  numTableiiv <- VUM.read numTablei nextTableiv
                  VUM.write numTablei1 v (numTableiv + numTableiiv)
              )
              $ VU.enumFromN 0 $ VU.length loopInfo
        )
        $ VU.enumFromN 0 $ shiftCnt
      --mapM_ (\tablei -> print =<< VU.freeze tablei) =<< V.freeze numTable
      acc@(next, sum) <-
        VU.foldM
          ( \acc@(next, sum) i -> do
              if aN .&. (shiftL 1 i) /= 0
                then do
                  nextTablei <- VM.read nextTable i
                  nnext <- VUM.read nextTablei next

                  numTablei <- VM.read numTable i
                  sump <- VUM.read numTablei next
                  return (nnext, sum + sump)
                else return acc
          )
          (0, 0)
          $ VU.enumFromN 0 $ shiftCnt
      print sum
  return ()

--雑多系
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