{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE DerivingStrategies         #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiWayIf                 #-}
{-# LANGUAGE RankNTypes                 #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeApplications           #-}
{-# LANGUAGE UndecidableInstances       #-}
import           Control.Monad
import           Control.Monad.ST
import qualified Control.Monad.State.Strict   as SS
import           Control.Monad.Trans.State
import           Data.Bits
import qualified Data.ByteString.Char8        as BS
import           Data.Char
import           Data.List
import           Data.Maybe
import           Data.Proxy
import           Data.Sequence                (Seq ((:<|), (:|>)), ViewL ((:<)),
                                               ViewR ((:>)), viewl, viewr, (<|),
                                               (><), (|>))
import qualified Data.Sequence                as Seq
import qualified Data.Set                     as S
import           Data.STRef
import qualified Data.Vector                  as V
import qualified Data.Vector.Mutable          as VM
import qualified Data.Vector.Unboxing         as VU
import qualified Data.Vector.Unboxing.Mutable as VUM
import           Numeric

main :: IO ()
main = do
  n <- readLn @Int

  print $ solve n

  return ()



solve :: Int -> Int
solve n = flip SS.evalState 0 $ do
  forM_ [1..n-1] $ \i -> do
    let fs = product $ map (\(_,f) -> f+1) $ primeFactors (n-i)
    SS.modify' (+ fs)
  SS.get





type Prime = Int
type Factor = Int

-- nの素因数分解リスト
primeFactors :: Int -> [(Prime, Factor)]
primeFactors n = filter (\x -> snd x /= 0) $ VU.toList $ factorize n

-- nを素因数分解する
factorize :: Int -> VU.Vector (Prime,Factor)
factorize n = VU.create $ do
  let sn = sqrtn n
  vp <- VUM.replicate (sn+1) True
  vf <- VUM.replicate (gg n) (0,0)
  ir <- newSTRef 0
  kr <- newSTRef n
  VUM.write vp 0 False
  VUM.write vp 1 False
  forM_ [2..sn] $ \p -> do
    b <- VUM.read vp p
    i <- readSTRef ir
    k <- readSTRef kr
    when b $ do
      forM_ [2*p,3*p..sn] $ \j -> VUM.write vp j False
      let (a, m) = ff k p
      VUM.write vf i (p, a)
      when (a /= 0) $ do
        writeSTRef ir (i+1)
        writeSTRef kr m
  i <- readSTRef ir
  k <- readSTRef kr
  when (k /= 1) $ VUM.write vf i (k, 1)
  return vf


-- nの平方根を超えない、最大の整数を求める
-- Double を経由しているので、誤差に起因する超過が無いかチェックする
sqrtn :: Int -> Int
sqrtn n = let m = floor $ sqrt $ fromIntegral n
          in if n >= m^2 then m else m - 1

-- k = p^a * m
-- を満たす(a, m)を求める
ff :: Int -> Int -> (Int, Int)
ff k p = go k 0
  where go :: Int -> Int -> (Int, Int)
        go m a = if m `mod` p == 0
                 then go (m `div` p) (a + 1)
                 else (a, m)


-- nのユニークな素因数の個数の（ナイーブな）上界を求める
-- sqrtn n の（非ユニークな）素因数の個数は、sqrt n <= 2^m を満たすm以下である。
-- そのため、mに1を加えたものが、上界となる。（sqrt n より大きな素因数は高々1個しかないため）
gg :: Int -> Int
gg n = let m = ceiling $ logBase 2 $ fromIntegral $ sqrtn n
       in if n <= 2^m then m + 1 else m + 2





-- converter
unconsChar :: StateT BS.ByteString Maybe Char
unconsChar = StateT BS.uncons

unconsInt :: StateT BS.ByteString Maybe Int
unconsInt = StateT $ BS.readInt . BS.dropWhile isSpace

unconsInteger :: StateT BS.ByteString Maybe Integer
unconsInteger = StateT $ BS.readInteger . BS.dropWhile isSpace

-- 1D Data
-- for list
readLnAsListWith :: StateT BS.ByteString Maybe a -> IO [a]
readLnAsListWith !st = unfoldr (runStateT st) <$> BS.getLine

-- for boxed vector
readLnAsVecWith :: StateT BS.ByteString Maybe a -> Int -> IO (V.Vector a)
readLnAsVecWith !st !n = V.unfoldrN n (runStateT st) <$> BS.getLine

-- for unboxed vector
readLnAsUVecWith :: VU.Unboxable a => StateT BS.ByteString Maybe a -> Int -> IO (VU.Vector a)
readLnAsUVecWith !st !n = VU.unfoldrN n (runStateT st) <$> BS.getLine

-- example: 1D tuple vector
readLnAsUVecWith2Tuple :: VU.Unboxable a => StateT BS.ByteString Maybe a -> Int -> IO (VU.Vector (a,a))
readLnAsUVecWith2Tuple !st !n = VU.replicateM n $ (\vec -> (vec VU.! 0, vec VU.! 1)) <$> readLnAsUVecWith st 2


-- 2D Data
-- n: number of lines
-- m: number of values per a line

-- for boxed vector
readLnAs2DVecWith :: StateT BS.ByteString Maybe a -> Int -> Int -> IO (V.Vector a)
readLnAs2DVecWith !st !n !m = V.unfoldrN (n * m) (runStateT st) . BS.concat <$> replicateM n BS.getLine

readLnAs2DUVecWith :: VU.Unboxable a => StateT BS.ByteString Maybe a -> Int -> Int -> IO (VU.Vector a)
readLnAs2DUVecWith !st !n !m = VU.unfoldrN (n * m) (runStateT st) . BS.concat <$> replicateM n BS.getLine
