-3

Given a number N ending in 1,3,7 or 9.

There will always exist a number M which when cubed ends with the same original number N. M need never have more digits than N.

Example:- N=123. M=947. (947)^3=849278123. Here (947)^3 ends with N(which is 123).

Write a program which takes N as input and finds M, where M is a number of atmost same number of digits as N, which when cubed ends in N.

I wrote the code as:

#include "iostream"
#include "math.h"
using namespace std;

int main()
{
    long long int t,p,j,i,d,c,s;
    cin>>t;
    long long int *n= new long long int[t];
    for(i=0;i<t;i++)
    {
        cin>>n[i];
    }
    for(i=0;i<t;i++)
    {   d=0; j=1;
        p=n[i];
        while(p)
        {
            d++;
            p=p/10;

        } p=n[i];
        s= pow(10,d);
        while(1)
        {
            c=j*j*j;
            if(c%s==p){break;}
            j++;

        }
    cout<<j<<endl;
     }
    return 0;
}

The time limit is 1 second. The time limit exceeds 1.

P0W
  • 46,614
  • 9
  • 72
  • 119

3 Answers3

4

There are quite a few things you can do. First - notice that a cube ending in an odd number must have started as an odd number - so only try odd numbers for M. Factor 2 in time saved.

Next - to find the last 3 digits of a number, just do number % 1000. And don't use pow. It is very slow. See my trick for finding the magnitude of the number.

You end up with something like this:

long int N, M, div;

printf("what is the value of N?\n");
scanf("%d", &N);
// test that it is reasonable before continuing...
// I did not write that code, but you should (size of N, and does it end in 1, 3, 7, or 9?

// find out how many digits N has:
div = 1;
while(N / div > 0) {
  div *= 10;
}

// now loop around odd M
for(M = 1; M < div; M+=2) {
  if( (M*M*M)%d==N) break;
}
// when you come out of this loop, M is the number you were looking for.

One final tweak - take a look at the cubes of numbers.

1*1*1 = 1
3*3*3 = 27

7*7*7 = 343
9*9*9 = 729

From this you conclude that if N ends in 1, you can check just numbers ending in 1:

for(M=1; M<div; M+=10) {

similarly for the other values (3 - start with M=7; 7 - start with M=3; 9 - start with M=9). Now we have a factor 10x faster code...

May not be enough to win the competition but it should help...

EDIT just ran the following code, and it gave the same answer you had above in 0.02 seconds (after 10,000 times going around the algorithm) - that's about 20 microseconds to find M just once... Note - updated m1 array so code should work even for "valid" numbers ending in 5 (although there is no guarantee that a number will exist - and the question explicitly asked about numbers ending in 1, 3, 7 and 9).

#include <stdio.h>
#include <time.h>

int main(void) {
    long long int N, M, div;
    long long int m1[] = {0, 1, 0, 7, 0, 5, 0, 3, 0, 9};
    time_t start, end;
    int ii;
    printf("what is the value of N?\n");
    scanf("%lld", &N);
    // test that it is reasonable before continuing...
    // I will leave that for you to do

    start = clock();
    // now starts the main loop
    // I go around it 10,000 times to get a "reasonable accuracy" since the clock()
    // function is not very granular (it was giving me "elapsed time zero")
    // obviously for competition you want to do this just once!
    for (ii = 0; ii < 10000; ii++) {
      // find out how many digits N has:
      div = 1;
      while(N / div > 0) {
        div *= 10;
      }

      // now try possible values of M - given the last digit of N
      // we know what the last digit of M should be
      // so we can start with that number, then take steps of 10
      for(M = m1[N % 10]; M < div; M+=10) {
        if( ( M * M * M ) % div == N ) break;
      }

    } // do it 10,000 times to get some time on the clock

   // when you come out of this loop, M is the number you were looking for.
   // since the loop stops at div, it should never be larger than N
    printf("M is now %lld\n", M);

    printf("M cubed is %lld which ends in %lld\n", M * M * M, ( M * M * M ) % div);

    end = clock();

    printf("Time taken: %f sec\n", ((float)(end - start) ) / CLOCKS_PER_SEC);
}
Floris
  • 45,857
  • 6
  • 70
  • 122
  • its still Time limit exceede.. and we have the original no in the end.. not only three digits – Swapnanil Saha Oct 19 '13 at 18:55
  • I don't know when you start your timer, or what platform you are running on. I just ran my code, adding a 10,000 times loop (after getting the input N, and before printing the output M). This took 0.13 seconds to run - or 13 microseconds to find M just once. Could it be that your timer includes the time it takes you to input the numbers (which is the slowest step in the program)? – Floris Oct 19 '13 at 19:18
  • it was not exceeding tht earlier – Swapnanil Saha Oct 19 '13 at 19:23
  • Try running the exact code I just posted, and use `123` as input. – Floris Oct 19 '13 at 19:23
  • @SwapnanilSaha: are you aware the posted code calculates the result **10,000 times**, instead of only once? If you adjusted for that, instead of simply copied-and-pasted this code, then it *may* exceed 0.0005 seconds -- but not by an amount of time you'd notice. – Jongware Oct 19 '13 at 20:03
  • @Floris: why does it fail on `125`? It should answer `165`, no? – Jongware Oct 19 '13 at 20:32
  • "A number ending in 1, 3, 7, or 9" was the task given... you could make the 6th element in the `m1` array `5`, then it will probably work. – Floris Oct 19 '13 at 20:33
  • Ah, sorry, my bad! Was there anything in the assignment about not using loops or if/else as well? (There usually is, in this kind of "questions"...) – Jongware Oct 19 '13 at 20:38
  • @Jongware I have updated code so it should work for _some_ numbers ending in `5`. This appears to be a "write fast code" assignment / "competition". I thought it was pretty fast; no idea why it's so slow for Swapnanil. He's been conspicuously quiet - guessing it's bedtime in his time zone. – Floris Oct 19 '13 at 20:40
  • @Floris: I'd rather think it's meant to separate plain logic coding from .. whatever the OP did. I cannot *but* make it work faster than 0.0001 seconds. – Jongware Oct 19 '13 at 20:46
1

The brute force method -- loop over all possibilities. Applied Math could probably run circles around this, but for now I let Applied Logic rule. It takes 0.021337 seconds to find the answer 10,000 times; running it once takes 0.000004 seconds, and that's with pretty generous rounding.

By way of bonus, it also seems to work for values ending in '5'.

(Edit) Applied Logic suggests you don't have to check for M > 1000. After all, (1000+M)³ = 1000³ + 3*M²*1000 + 3*M*1000² + M³, and since we are using mod everything above 1000 is cancelled out and the calculation reduces to M³ -- I wonder, perhaps we should move this question to math.stackexchange.com.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

int main(int argc, char **argv)
{
    long long int N, M, val;
    int ii;
    time_t start, end;

    if (argc == 2)
        N = strtoul (argv[1], NULL, 10);
    else
    {
        printf("what is the value of N?\n");
        scanf("%lld", &N);
    }

    if (~N & 1)
    {
        printf ("invalid input\n");
        return EINVAL;
    }

    start = clock();
    for (ii=0; ii<10000; ii++)
    {
    for (M=1; M<1000; M+=2)
    {
        val = M%1000;
        val = val*val*val;
        if ((val % 1000) == N)
            break;
    }
    }
    end = clock();

    printf("For N=%lld, M=%lld, cubed is %lld which ends in %lld\n", N, M, M*M*M, (M*M*M)%1000);

    printf("Time taken: %f sec for 10,000 loops\n", ((float)(end - start) ) / CLOCKS_PER_SEC);

    return 0;
}
Jongware
  • 22,200
  • 8
  • 54
  • 100
  • 1
    Why are you allowing M to go all the way up to 100,000? If N is no more than three digits, and M is never greater than N (per the question), you are setting a very generous upper limit... But like you, I am puzzled that the original code would appear so slow (unless, as I suspect, he is timing the entire program, including the input loop...) – Floris Oct 19 '13 at 20:52
  • @Floris: yeah I already adjusted it. See (Edit) comment. But M has *no more digits* than N, it still can be larger (although for `125` a correct answer is `5`). – Jongware Oct 19 '13 at 20:57
  • Which is why I was doing the trick with `div` in my code - find the number that's certainly big enough but not crazy big. And then I found that you may have to go past N. If N=11, M = 71... Actually you need to replace several places where I have `1000` with `div`. I will update my code. – Floris Oct 19 '13 at 21:10
0

Let's take the number N and calculate its third power (modulo 1000) repeatedly:

N0 = N
N1 = N0^3 mod 1000
N2 = N1^3 mod 1000
N3 = N2^3 mod 1000
...

It appears that if N = 123, then N19 = 947, which calculates the cubic root rather easily. It is possible to prove that this procedure will give us an answer (the Stack Overflow site is not an appropriate place for the proof, so just believe me or ask on Math Overflow). It is not evident that this procedure is faster than any other, but it seems to be fast enough; as far as I understand, it's supposed to be faster than the brute-force approach with any number of improvements.

Some code (based on original code):

while(1)
{
    c = j * j * j % s;
    if (c == p)
       break;
    j = c;
}

Note: this assumes that the calculation j * j * j doesn't overflow (is less than 2^63). This is good enough for N of up to 6 digits, which may or may not be good enough.

Community
  • 1
  • 1
anatolyg
  • 26,506
  • 9
  • 60
  • 134