int prime[MAXM / 10]= {0}; bool visit[MAXM]= {false}; int pcnt = 0; int mu[MAXM]= {0}, sumu[MAXM]= {0}; voidlinear_sieve(){ sumu[1] = mu[1] = 1; for (int i = 2; i <= MAX; i ++) { if (! visit[i]) { prime[++ pcnt] = i; mu[i] = - 1; } for (int j = 1; j <= pcnt && i * prime[j] <= MAX; j ++) { visit[i * prime[j]] = true; if (! (i % prime[j])) break; mu[i * prime[j]] = - mu[i]; } sumu[i] = sumu[i - 1] + mu[i]; } }
tr1::unordered_map<int, int> mapmu; intmu_sieve(int n){ if (n <= MAX) return sumu[n]; if (mapmu[n]) return mapmu[n]; int total = 1; for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); total -= (r - l + 1) * mu_sieve (n / l); } return mapmu[n] = total; } LL f[MAXK]= {0}; LL sumr[MAXM]= {0}; // sigma ([(j, k) = 1]) intGCD(int a, int b){ return ! b ? a : GCD (b, a % b); } voidr_sieve(){ for (int i = 1; i <= K; i ++) f[i] = f[i - 1] + (GCD (i, K) == 1); } intrval(int n){ return (n / K) * f[K] + f[n % K]; }
map<pair<int, int>, int> mapl; LL l_solve(int n, int k){ // S(n, K) if (! n) return0; pair<int, int> ret = make_pair (n, k); if (mapl[ret]) return mapl[ret]; if (k == 1) return mu_sieve (n); LL total = 0; for (int i = 1; i * i <= k; i ++) if (! (k % i)) { if (mu[i]) total += l_solve (n / i, i); if (i * i != k && mu[k / i]) total += l_solve (n / (k / i), k / i); } return mapl[ret] = total; }
intmain(){ linear_sieve (); scanf ("%d%d%d", & N, & M, & K); r_sieve (); LL ans = 0, pre = 0; for (int l = 1, r; l <= min (N, M); l = r + 1) { r = min (N / (N / l), M / (M / l)); LL pl = l_solve (r, K); ans += 1ll * (pl - pre) * (N / l) * rval (M / l); pre = pl; } cout << ans << endl;