This Is Why We Code

Let ϕ ( n ) \phi(n) denote the Euler's totient function .

There exists only one positive integer a 1 0 10 a \le 10^{10} such that ϕ ( a ) = ϕ ( a + 1 ) = ϕ ( a + 2 ) . \phi(a)=\phi(a+1)=\phi(a+2).

Find the remainder when that number a a is divided by 1729.


The answer is 1728.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

5 solutions

Nitish Joshi
Mar 5, 2016

I have solved it using C++. I am pretty new to programming, so my program was not at all efficient. Could anyone suggest an efficient way/algorithm to solve this problem?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream.h>
#include<conio.h>
long int gcd(long int a, long int b)
{
 while(a!=b)
 {
  if(a>b)
  a=a-b;
  if(b>a)
  b=b-a;
 }
 return a;
}
long int phi(long int c)
{
 long int d=0;
 for(long int i=1;i<c;i++)
 {
  if(gcd(c,i)==1)
  d++;
 }
 return d;
}
void main()
{
 clrscr();
 for(long int j=1;j<100000000;j++)
 {
  if(phi(j)==phi(j+1) && phi(j+1)==phi(j+2))
  cout<<j;
 }
getch();
}

Answer: 5186

Note that I have checked the numbers only till 1 0 8 10^8 as I was having some problems using long int data type for numbers greater than that.

I think there is some optimizations you can do, first the obvious : you compute phi 4 times for each value, you should store the previous results in 2 variables, then phi should compute faster by using the primes factors of n n , as you have to test divisibility n \sqrt{n} times in the worst case, instead of computing n times the gcd. The formula tu use is ϕ ( n ) = ( p 1 ) p i 1 \phi (n) = \sum (p - 1)p^{i - 1} where p are primes factors of n and i their power.

I have come with two algorithms using this formula and storing the previous value of ϕ \phi The first one use this fact : if p divide n then ϕ ( n ) = ( p δ ) ϕ ( n / p ) \boxed{ \phi (n) = (p - \delta) \phi (n / p) } where δ \delta is 1 if p doesn't divide n / p, else 0.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stdlib.h>
#define U unsigned
#define SIZE 100000003
typedef U long big;

big     *euler_list;

big     phi(big n)
{
    big p;
    div_t   rq;

    if ((n & 1) == 0)
        return euler_list[n >> 1] * (1 + ((n & 2) == 0));
    p = 3;
    while (p * p <= n)
    {
        rq = div(n, p);
        if (rq.rem == 0)
            return euler_list[rq.quot] * (p - (rq.quot % p != 0));
        p += 2;
    }
    return n - 1;
}           

int     main()
{
    big *end;
    big *ph;
    big n = 2;

    euler_list = malloc(SIZE * sizeof(*euler_list));
    euler_list[1] = 1;
    ph = euler_list + n;
    end = euler_list + SIZE;
    while (ph < end)
    {
            *ph = phi(n);
        if (*ph == *(ph - 1) && *(ph - 1) == *(ph - 2))
            printf("a = %ld\n", n - 2);
        //printf("phi[%lld] = %lld\n", n, *ph);
        ph++;
        n++;
    }
    return 0;
}

Another method is to fill the array by multiplying each multiple of a prime p by p - 1 and multiplying by p each multiple of a power 2 \geq 2 . This is faster because we travel the array in simple and predictable way, there is no cache miss nor division test. The p values are found when a 1 is encountered in the array (meaning p is not multiple of a previous prime hence p is prime)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#define U unsigned
#define SIZE 100000003
typedef U long  big;


int     main()
{
    big *euler_list;
    big n;
    big k;
    big km;
    big m;

    n = SIZE;
    euler_list = malloc(SIZE * sizeof(*euler_list));
    while (n--)
        euler_list[n] = 1;

    n = 2;
    do
    {
        k = n;
        m = n - 1;
        while (k < SIZE)
        {
            km = 0;
            while ((km += k) < SIZE)
                euler_list[km] *= m;
            m = n;
            k *= n;
        }
        do {
//          printf("phi[%ld] = %ld\n", n, euler_list[n]);
            if ( euler_list[n] == euler_list[n - 1]
            && euler_list[n] == euler_list[n - 2] && n != 2)
                printf("a = %ld\n", n - 2);
            n++;
        } while (n < SIZE && euler_list[n] != 1);
    } while (n < SIZE);
    return 0;
}

As nobody has 80 Gigabytes of ram, we cannot compute the full 1 0 10 10^{10} using 64 bits integers. But by storing the primes 1 0 5 \leq 10^{5} and their power 1 0 10 \leq 10^{10} , and using chunks of 1000000 integer, we can construct ϕ \phi and reconstruct the n's by using the previous code. We reconstruct the n's as if they have not been fully reconstructed, let say m n m \le n , we know that n / m n / m must be a prime outside the list, and we finish p h i phi construction by multiplying by n / m 1 n / m - 1

Yes, I may have overthink this one :)

Mathieu Guinin - 5 years, 2 months ago

Log in to reply

Thanks for your inputs. I actually used brute force method but I see how efficient your algorithms are.

Nitish Joshi - 5 years, 2 months ago
Pranjal Jain
Mar 24, 2016

Here's quite efficient code, using two sieves.

I can just change N from 1 0 5 10^5 to bigger value if no value is found.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <bits/stdc++.h>
using namespace std;

const int N=100000;
bool mysieve[N];
int eulerPhi[N];

void primesieve() {
    for(int i = 0; i <= N;++i) {
        mysieve[i] = true;
    }
    mysieve[0] = false;
    mysieve[1] = false;
    for(int i = 2; i * i <= N; ++i) {
        if(mysieve[i] == true) {
            for(int j = i * i; j <= N ;j += i)
                mysieve[j] = false;
        }
    }
}

void eulerSieve(){
    for (int i = 0; i <= N; i++)
        eulerPhi[i] = i;
    for(int i=1;i<=N;i++){
        if(mysieve[i]){
            for (int j = i; j <= N; j += i)
                eulerPhi[j] -= eulerPhi[j] / i;
        }
    }
}

int main(){
    primesieve();
    eulerSieve();
    for(int i=0;i<N-2;i++){
        if(eulerPhi[i]==eulerPhi[i+1] && eulerPhi[i]==eulerPhi[i+2]){
            cout<<i;
            return 0;
        }
    }
    return 0;
}

Massimo 22
Nov 27, 2017

Python code: (seems to be pretty efficient. My trick was to brute force ϕ \phi , instead of wasting bytes on finding factors.)

import fractions

def phi(n):
    amount = 0
    for k in range(1, n + 1):
        if fractions.gcd(n, k) == 1:
             amount += 1
            return amount

for i in range(1, 10000000):

    if phi(i) == phi(i + 1) == phi(i + 2):
        print i % 1729

I could only do 2 9 2^9 because my IDE wouldn't let me go higher.

Soumava Pal
Mar 12, 2016

I am not a very good coder, and while I wrote a program from this, I could not check upto 1 0 10 10^{10} because I am comfortable in Python where if we give such a big range it shows Memory Error, so I just extended the range till I was getting a solution.

I got 5186 that way, and I must say, that Nitish's code is exactly what I had written( we only have to change the syntax from C++ to python ).

But more interestingly, there is another problem for which I needed to know ϕ ( 1 ) \phi(1) and I had forgotten whether the definition of Totient had a 'less than equal to n' or 'less than n' condition. So I went here . On scrolling down I found some nice looking properties, and I found a statement which stated exactly what this problem asked and remembered about this problem.

The properties there seem quite interesting exercises to prove.

Samarth Agarwal
Mar 11, 2016

My code in java ``class sam

{

public static void main(String ar[])

{

long i=0l;

for(i=2;i<=10000000000l;i++)

  if(phi(i,1)==phi(i+1,1) && phi(i,1)==phi(i+2,1))

    {

      System.out.println(i%1729);

    }

}

public static long phi(long i,long m)

{

long j=0l,k=0l;

for(j=m+1;j<=i;j++)

{

  if(i%j==0)

  {

    for(k=2;k<=j/2;k++)

    {

      if(j%k==0)

        break;

    }

    if(k==((j/2)+1))

      return phi((i*(j-1))/j,j);

  }

}

return i;

}

}
``

this gives the answer as 5186 and can be used till (i+2) is under the limit of long

for clarity anf formatting, I would give this an extra four spaces. It keeps going in an out of code.

massimo 22 - 3 years, 6 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...