For a given number n calculate the value of G, where
G =
Here GCD(i, j)
means the greatest common divisor of integers i and j.
For those who have trouble
understanding summation notation, the meaning of G is given in the following
code:
g = 0;
for (i = 1; i < n; i++)
for (j = i + 1; j <= n; j++)
g += gcd(i,
j);
Input. Consists of no more than 20000 lines. Each line contains an
integer n (1 < n < 4 * 106). Input is
terminated by a line containing a single zero and should not be processed.
Output. For each input number n print in a separate line the
corresponding value of G. The value of G will fit in a 64-bit signed integer.
Sample
input |
Sample
output |
6 10 100 200000 0 |
20 67 13015 143295493160 |
number theory – Euler
function
Let d[k] = .
For example d[2] = = = GCD(1, 2) = 1.
You can see that d[k] = =
+ = d[k – 1] +
It remains to show how to
calculate the value of faster than usual summation.
Lema. Let n is divisible
by d and GCD(x, n) = d. Then x = dk for some positive
integer k. From the relation GCD(dk, n)
= d it follows that GCD(k, n/d) = 1.
Theorem. Let f(n) = . Then f(n) = for all divisors d of number n. indicates here the
Euler function.
Proof. The number of such i,
for which GCD(i, n) = 1, equals to . The number of such i
(i ≤ n), for which GCD(i, n) = d
(d is a divisor of n, i
= dk), equals to the number of such k (k ≤ n / d), for which GCD(k, n/d) = 1 or . The value of GCD(i,
n) can be only the divisors of n. To find the value f(n)
it remains to sum the values over all divisors d of n.
Example
Consider the direct
calculation: f(6) = =
GCD(1, 6) + GCD(2, 6) + GCD(3,
6) + GCD(4, 6) + GCD(5, 6) + GCD(6, 6) =
1 + 2 + 3 + 2 + 1 + 6 = 15
Consider the calculation
using the formula:
f(6) = = + + + =
= + + + = 2 + 4 + 3 + 6 = 15
In the first and in the
second case 15 is the sum of two units (), two doules (), one triple () and one sextuple ().
Algorithm realization
Declare the arrays. fi[i] stores the value of the Euler
function j(i).
#define MAX
4000010
long long d[MAX], fi[MAX];
The function FillEuler fills the array fi
so that fi[i] = j(i), i < MAX.
void
FillEuler(void)
{
Initially set the value of fi[i] equal to i.
for(i = 1; i
< MAX; i++) fi[i] = i;
Each even number i
has a prime divisor p = 2. To speed
up the function working time, process it separately. For each even number i set fi[i] = fi[i] * (1 – 1 / 2)
= fi[i] / 2.
for(i = 2; i
< MAX; i+=2) fi[i] /= 2;
Enumerate all the possible odd divisors i = 3, 5, 7, … .
for(i = 3; i
< MAX; i+=2)
if(fi[i] ==
i)
If fi[i] =
i, then the number i is prime. The number i is a prime divisor for any j, represented in the form k * i
for any positive integer k.
for(j =
i; j < MAX; j += i)
If i is a prime
divisor of j, then set fi(j) = fi(j) * (1 – 1/i).
fi[j] -= fi[j]/i;
}
Before calling the function f the values d[i] already contain j(i). The
body of the function f adds to d[j] the
values so that when the function finishes its work, the value d[j] contains according to the
formula given in the theorem.
void f(void)
{
int i,
SQRT_MAX = sqrt(1.0*MAX);
for(i = 2; i
<= SQRT_MAX; i++)
{
d[i*i] += i * fi[i];
The number i is
a divisor of j. So we need to add to
d[j] the value of . Since the number j
has also a divisor j / i, add to d[j] the value of = . If i2
= j, add to d[j] not two terms, but only one = .
// for(j = i * i +
i; j < MAX; j += i)
// d[j] += i * fi[j / i] + j / i * fi[i];
We can avoid integer division in implementation. To do
this note, that since the value of the variable j is incremented each time by i,
then the value j / i will be increase by one in a loop. Set
initially k = j / i = (i * i
+ i) / i = i + 1 and then
increase k by 1 in each iteration.
for(j = i *
i + i, k = i + 1; j < MAX; j += i, k++)
d[j] += i * fi[k] + k * fi[i];
}
Its sufficiently to continue the loop by i till , because if i is a
divisor of j and i > , then considering the fact that j / i < we can state that the
divisor i of the number j was taken in account when we
considered the divider j / i.
}
The
main part of the program. Initialize the arrays. Let d[i] = j(i).
memset(d,0,sizeof(d));
FillEuler();
memcpy(d,fi,sizeof(fi));
f();
for(i =
3; i < MAX; i++)
d[i] += d[i-1];
while(scanf("%lld",&n),n)
printf("%lld\n",d[n]);
Java realization
import
java.util.*;
public class Main
{
public final static int MAX = 4000001;
public static long d[] = new long[MAX];
public static int fi[] = new int[MAX];
static void FillEuler()
{
for(int i = 2; i < MAX; i++) fi[i] = i;
for(int i = 2; i < MAX; i+=2) fi[i] /= 2;
for(int i = 3; i < MAX; i+=2)
if(fi[i] == i)
for(int j = i; j < MAX; j += i) fi[j] -= fi[j]/i;
}
static void f()
{
int SQRT_MAX = (int)Math.sqrt(1.0*MAX);
for(int i = 2; i <= SQRT_MAX; i++)
{
d[i*i] += i * fi[i];
for(int j = i * i + i, k = i + 1; j < MAX; j += i, k++)
d[j] += i * fi[k] + k * fi[i];
}
}
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
FillEuler();
for(int i = 0; i < MAX; i++)
d[i] = fi[i];
f();
for(int i = 3; i < MAX; i++)
d[i] += d[i-1];
while(true)
{
int n = con.nextInt();
if (n == 0) break;
System.out.println(d[n]);
}
}
}