package main
import (
"fmt"
)
const MAX_SIEVE = 5000000
var prefPhi []uint32
var primes []int
var memoPhi map[int]uint32
func initSieve() {
prefPhi = make([]uint32, MAX_SIEVE+1)
phi := make([]uint32, MAX_SIEVE+1)
for i := 1; i <= MAX_SIEVE; i++ {
phi[i] = uint32(i)
}
for i := 2; i <= MAX_SIEVE; i++ {
if phi[i] == uint32(i) {
for j := i; j <= MAX_SIEVE; j += i {
phi[j] = phi[j] / uint32(i) * uint32(i-1)
}
}
}
for i := 1; i <= MAX_SIEVE; i++ {
prefPhi[i] = prefPhi[i-1] + phi[i]
}
const MAX_PRIME = 13000000
isP := make([]bool, MAX_PRIME+1)
for i := 2; i <= MAX_PRIME; i++ {
isP[i] = true
}
for i := 2; i*i <= MAX_PRIME; i++ {
if isP[i] {
for j := i * i; j <= MAX_PRIME; j += i {
isP[j] = false
}
}
}
for i := 2; i <= MAX_PRIME; i++ {
if isP[i] {
primes = append(primes, i)
}
}
memoPhi = make(map[int]uint32)
}
func PhiSum(x int) uint32 {
if x <= MAX_SIEVE {
return prefPhi[x]
}
if val, ok := memoPhi[x]; ok {
return val
}
var res uint32 = uint32(x) * uint32(x+1) / 2
for l := 2; l <= x; {
q := x / l
r := x / q
res -= uint32(r-l+1) * PhiSum(q)
l = r + 1
}
memoPhi[x] = res
return res
}
type state struct{ X, D int }
var memoSD = make(map[state]uint32)
func S_dense(X int, D int) uint32 {
if X == 0 {
return 0
}
if D == 1 {
return PhiSum(X)
}
st := state{X, D}
if val, ok := memoSD[st]; ok {
return val
}
var p int
for _, pr := range []int{2, 3, 5, 7, 11} {
if D%pr == 0 {
p = pr
break
}
}
res := uint32(p-1)*S_dense(X, D/p) + S_dense(X/p, D)
memoSD[st] = res
return res
}
var n int
var sparse_sum [6]uint32
var D_c = [6]int{1, 1, 2, 6, 210, 2310}
func getMaxRatio(k int, phi int, p_idx int) float64 {
rem := n / k
ratio := float64(k) / float64(phi)
for i := p_idx; i < len(primes); i++ {
p := primes[i]
if p > rem {
break
}
ratio *= float64(p) / float64(p-1)
rem /= p
}
return ratio
}
func dfs(p_idx int, k int, phi int) {
for i := p_idx; i < len(primes); i++ {
p := primes[i]
if k*p > n {
break
}
possible := false
for c := 2; c <= 5; c++ {
if (k*p)%D_c[c] != 0 {
nr := float64(k*p) / float64(phi*(p-1))
if nr >= float64(c) {
possible = true
break
}
mr := getMaxRatio(k*p, phi*(p-1), i+1)
if mr >= float64(c) {
possible = true
break
}
}
}
if !possible {
break
}
nk := k * p
nphi := phi * (p - 1)
for nk <= n {
nr := float64(nk) / float64(nphi)
for c := 2; c <= 5; c++ {
if nk%D_c[c] != 0 && nr >= float64(c) {
sparse_sum[c] += uint32(nphi)
}
}
dfs(i+1, nk, nphi)
nk *= p
nphi *= p
}
}
}
func main() {
initSieve()
if _, err := fmt.Scan(&n); err != nil {
return
}
dfs(0, 1, 1)
var totalWPhi uint32
totalWPhi += S_dense(n, 1)
totalWPhi += S_dense(n/2, 2) + sparse_sum[2]
totalWPhi += S_dense(n/6, 6) + sparse_sum[3]
totalWPhi += S_dense(n/210, 210) + sparse_sum[4]
totalWPhi += S_dense(n/2310, 2310) + sparse_sum[5]
var sumK uint32 = uint32(n % (1 << 32))
var sumK1 uint32 = uint32((n + 1) % (1 << 32))
var totalK uint32
if sumK%2 == 0 {
totalK = (sumK / 2) * sumK1
} else {
totalK = sumK * (sumK1 / 2)
}
ans := totalK - totalWPhi
fmt.Println(ans)
}