Get powers of a perfect power number - java

I have a problem which is to find the 2 powers of any number (numbers that don't have any powers such as 5 will return null), powers being and 2 integer numbers that when added power to return the said number. Here are some examples:
4 -> {2, 2}
5 -> null
6 -> null
7 -> null
8 -> {2, 3}
10 -> null
etc...
Although my code below works, however its too slow, when passed through the problem (about 100 integer.max values) it takes over the set time (16 seconds), anything I could to optimize this code?
public static int[] isPerfectPower(int n) {
int limit = (int)Math.round((n/((double)5/2)));
for (int i = 2; i <= limit; i++) {
double result = Math.pow(n, (double)1/i);
result = (double)Math.round(result * Math.pow(10, 10)) / Math.pow(10, 10);
if((result == Math.floor(result))) return new int[] {(int)result, i};
}
return null;
}

Your input is no more than 2147483647, which means there are only so many possible answers. Here is an ordered list of all 108 perfect powers with a power of 5 or more.
2**5, 2**7, 3**5, 4**5, 2**11, 3**7, 5**5, 6**5, 2**13, 4**7, 7**5, 8**5, 9**5, 5**7, 10**5, 2**17, 11**5, 3**11, 12**5, 6**7, 13**5, 2**19, 14**5, 15**5, 7**7, 16**5, 17**5, 3**13, 18**5, 8**7, 19**5, 20**5, 21**5, 4**11, 9**7, 22**5, 23**5, 24**5, 2**23, 25**5, 10**7, 26**5, 27**5, 28**5, 11**7, 29**5, 30**5, 31**5, 32**5, 12**7, 33**5, 34**5, 5**11, 35**5, 36**5, 13**7, 4**13, 37**5, 38**5, 39**5, 40**5, 14**7, 41**5, 3**17, 42**5, 43**5, 44**5, 15**7, 45**5, 46**5, 47**5, 48**5, 16**7, 49**5, 50**5, 51**5, 6**11, 52**5, 17**7, 53**5, 54**5, 55**5, 2**29, 56**5, 57**5, 18**7, 58**5, 59**5, 60**5, 61**5, 19**7, 62**5, 63**5, 64**5, 65**5, 3**19, 5**13, 66**5, 20**7, 67**5, 68**5, 69**5, 70**5, 21**7, 71**5, 72**5, 7**11, 73**5
Therefore you only have to check for squares, cubes, and entrees of the list above.
A slightly more naïve method would be to check all ten powers 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. You do not need to check any other powers, as they are either non-prime or too large to ever work.

You can do it by factoring a number.
Lets n = p1^k1 * p2^k2 * p3^k3 where p1,p2,p3 = prime number.
Then a number will be perfect power if gcd(k1, k2, k3) != 1 (They need to have common divisor)..
Example:
2500 = 2^2 * 5^4
= 2^2 * (5^2)^2
= 2^2 * 25^2
= 50^2
This way you can calculate power of perfect powers.
Way 2:
Lets n = a^b ... you need to find a & b where b < log(n)...
Now u need to find a.. you can find a using binary search. this complexity log(a)...to calculate a^b1..... u need log(n) operation.
So complexity for all binary operation: (log(n) * log log(n))
Total complexiy : log(n) * (log(n) * log log(n))

As #Mark Dickinson suggested, the most efficient change to my code ( without completely changing it ) would be to cap my limit at 30 instead of 2/3 of n, as any number >2 with a power greater then 30 would exceed the Integer.max limit, therefore but adding an extra expression ( i < 30 ) would immensely speed up the code, the code will be displayed below.
public static int[] isPerfectPower(int n) {
for(int i = 2; i <= ((n < 30) ? n : 30) && i < 30; i++) {
double result = (double)Math.round(Math.pow(n, (double)1/i) * Math.pow(10, 10)) / Math.pow(10, 10);
if((result == Math.floor(result))) return new int[] {(int)result, i};
}
return null;
}

Related

the maximum n digit number possible in K steps

Can somebody help me with this problem?
Statement: - What is the maximum possible n digit number starting from 0 we can make in K steps
using only 2 operations:-
multiplying by 3 or incrementing by 2.
EXAMPLE :
N =2 K = 5;
-> (0->2->6->8->24->72) 72 IS THE ANSWER
N = 2 , K = 51 -> (0->2->6->8->10->30->32->96->98). 98 is the maximum we can get so need to check for rest of the moves.
My 2 state-recursive solution:-
public static void largestNDigitNumber(long[] highest, long maxValue, long k, long currentValue) {
if (highest[0] == (maxValue - 2)) return; //no need to do anything as we get 98 as highest.
if (k < 0) return; //checking for steps
if (highest[0] < currentValue && currentValue <= (maxValue - 2)) {
highest[0] = currentValue;
}
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue * 3));
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue + 2));
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long maxValue = (long) Math.pow(10, n);
long[] highest = new long[1];
largestNDigitNumber(highest, maxValue, (k - 1), 2);
if (highest[0] < (long) Math.pow(10, (n - 1))) {
System.out.println("-1"); // if it is not possible to make n digit in given steps
} else System.out.println(highest[0]);
}
when "k" is small it is giving the correct answer but for bigger values of "k", it does not show any input. for n=2 and k = 51, it does not show anything.
please help me to improve this code
The question is equivalent to asking what is the largest base 3 number that is less than 10^n/2, and has digit sum plus length less than or equal to k+1. (The answer is then double the base 3 number).
For example, N=2 K=5. What's the largest base 3 number that's less than 50, with length plus digit sum less than or equal to 6. Answer: 1100 (36 decimal), so the answer to the original question is 36*2=72.
For N=2, K=51, the largest base-3 number that's less than 50 is 2001 (49 decimal) and has length sum plus digit sum = 7, which is way less than K+1.
Given this representation, it's easy to solve the problem in O(n) time (in fact, you can solve it using pencil and paper). The length d of the base-3 number is as large as possible such that 3^d < 10^n/2 and d<=K. Then fill in the digits of the number greedily from the most-significant first until you have digit sum K+1-d (or you run out of digits).
Equivalence
First note that without loss of generality you can assume you never have three +2 operations in a row, since that can be done more efficiently by inserting a single +2 operation to before the most recent *3 (or simply replacing it by +2 * 3 if there's no *3 operation). Suppose you have represented the current number as a doubled base-3 number. A +2 operation corresponds to adding 1 to the bottom digit (this never overflows into the next column thanks to the observation above). A *3 operation moves all the digits up one column, introducing a 0 as the bottom digit. Note that because the number is doubled, the +2 operation adds just 1 to the base-3 number!
From this, you can see that you can count the number of operations from observation of the doubled base-3 number. Because *3 introduces a new digit, and +2 increases the digit sum by 1, so the number of operations is equal to the number of digits plus 1, plus the digit sum.
As an example. Suppose you have the doubled base-3 number 2 * 2101, then this is equivalent to 2 * (1+3*3*(1+3*(1+1)))) = (2 + 3*3*(2+3*(2+2))).
I tried something like this. it seems to work fine.
getMaxNumber(2, 5) ==> 72
getMaxNumber(2, 51) ==> 98
private int getMaxNumber(int n, int k){
int N = 0;
for (int i = 0; i < n; i++) {
N = N * 10 + 9;
}
int[] result = new int[1];
helper(N, k, 0, 0, result);
return result[0];
}
private void helper(int N, int K, int n, int k, int[] result){
if(n > N) return;
if(k <= K){
result[0] = Math.max(result[0], n);
}
if(n > 0)
helper(N, K, n * 3, k + 1, result);
helper(N, K, n + 2, k + 1, result);
}
Keeping with the style of your original recursive method. I modified it a bit to produce a working solution:
public static long largestNDigitNumber(int n, long currentK, long maxK, long currentValue) {
if (currentK > maxK || n < 1 || maxK < 1) return 0;
if (currentValue >= Math.pow(10, n))
return 0;
long c1 = largestNDigitNumber(n, currentK + 1, maxK, currentValue * 3);
long c2 = largestNDigitNumber(n, currentK + 1, maxK, currentValue + 2);
if (c1 == 0 && c2 == 0)
return currentValue;
return c1 > c2 ? c1 : c2;
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long largest = largestNDigitNumber(n, 0, k, 0);
System.out.println(largest); //98
}
This recursive method returns values here instead of using an array. Hence the check if one returned value is bigger than the other or they are both 0 before returning.
Both the +2 and *3 operations preserve odd/even parity, so starting from 0 we can only reach even numbers. We could start our search at the highest even number: 8, 98, 998, 9998 etc. and see what the shortest distance to 0 is.
If we are looking for the shortest distance, then there are less choices to make. If the current number is a multiple of 3 then there are two choices, either we divide by 3 or subtract 2. Otherwise the only choice is to subtract 2. I suspect that in the majority of cases, dividing by 3 is the better option, so that might be the first to try to keep the tree smaller.
If the minimum number of steps is less than K then as many divide by 3 operations as needed can be used to make the correct K
If the minimum number of steps is equal to K then the problem is solved.
If the minimum number of steps is more than K then you need to pick a lower starting number. Some even numbers will already have been covered as part of the initial calculation. You get those 'for free', provide you include a small amount of record keeping. You only need to examine large even numbers that were missed earlier due to a 'divide by 3' step.

Find closest value to determined multiplicated value

I have two values. One is static and equals 24
int A = 24;
and I have entries list :
[0, 21, 45, 76, 98]
All of occurences comes in loop and I want to get closest value which divides on A :
0 - 24
21 - 24
45 - 48
76 - 72
98 - 96
How to calculate this?
Using java8 you can stream the array or list and map that
public static void main(String[] args) {
int a = 24;
List<Integer> mL = Arrays.asList(0, 21, 45, 76, 98);
Map<Integer, Integer> m = mL.stream().collect(Collectors.toMap(Integer::intValue, x -> {
int r = a * (int) Math.round(x / (double) a);
return r == 0 ? a : r;
}));
System.out.println(m);
}
the output will be a map where the key is the values to analyse and the values are the closest delta to it
{0=24, 98=96, 21=24, 76=72, 45=48}
You could divide each value by a using floating point division, round it to the closest int and then multiply it back again by a:
int a = 24;
int[] values = new int[]{0, 21, 45, 76, 98};
int[] result =
Arrays.stream(values).map(v -> a * (int) Math.round(v / (double) a)).toArray();
To find the largest multiple x of a number n which is less than a given number a, you can use some arithmetic:
int x = n - n % a;
Now if you want to get the nearest multiple, whether larger or smaller than a, you can use an if statement:
if (a - x > (x + n) - a)
x = x + a
For a list of numbers, just loop over them or use the Stream API.
Assuming that the arrays are also integers, the correct approach for rounding an integer a to the nearest multiple of integer n is as follows:1
(a + n/2) / n * n
How this works
Hopefully the a / n * n approach should be familiar as an approach to get floor-like behaviour, due to the way integer maths works. The n/2 is a bias to give you round-like behaviour instead.2
Things to be aware of
Exact ties are rounded upward.
Inputs within n / 2 of the maximum representable value will cause this to fail.
Comparison with other answers
The floating-point approaches aren't guaranteed to give the right answer for all input values, due to the limitations of floating-point arithmetic.
Using double may work if the inputs are ints (although I'm not sure what the proof is). But it certainly won't be sufficient for longs.
This integer approach may be equivalent to #CodeApprentice's answer, I'm not sure. But this approach avoids the conditional.
1. The boilerplate stream/loop code to get this to work for multiple input values is left as an exercise for the reader.
2. And for completeness, if you use a bias of n-1, you get ceil-like behaviour!
One approach is to take the remainder and see if you need to add or substract from the given number to get closest number that divides. If remainder is less then half of A then substract remainder from the number otherwise add to it the difference between remainder and A. Also as a quick exit check if number is less then A the closest one is A itself.
public static int[] closest(int a, int[] b){
int[] result = new int[ b.length ];
int halfOfA = a/2;
for (int i = 0; i < b.length; i++){
if ( b[i] <= a ){
result[i] = a;
}else{
int rem = b[i] % a;
if (rem < halfOfA) result[i] = b[i] - rem;
else result[i] = b[i] + (a - rem);
}
}
return result;
}
You can do like this :
iterate until your are as near as possible of the value (when distance is less than A/2
private static int closestTo(int a, int i) {
int res = a;
while (Math.abs(res - i) > (a / 2.0) && res< i + a) {
res += a;
}
return res;
}
And use like
public static void main(String[] args) {
int A = 24;
int[] tab = new int[]{0, 21, 45, 76, 98};
for (int i : tab) {
System.out.println(i + " - " + closestTo(A, i));
}
}

Given a stock of integers 0-9, what is the last number I can write before I run out of some integer?

As the title says, given a stock of integers 0-9, what is the last number I can write before I run out of some integer?
So if I'm given a stock of, say 10 for every number from 0 to 9, what is the last number I can write before I run out of some number. For example, with a stock of 2 I can write numbers 1 ... 10:
1 2 3 4 5 6 7 8 9 10
at this point my stock for ones is 0, and I cannot write 11.
Also note that if I was given a stock of 3, I could still write only numbers 1 ... 10, because 11 would cost me 2 ones, which would leave my stock for ones at -1.
What I have come up so far:
public class Numbers {
public static int numbers(int stock) {
int[] t = new int[10];
for (int k = 1; ; k++) {
int x = k;
while (x > 0) {
if (t[x % 10] == stock) return k-1;
t[x % 10]++;
x /= 10;
}
}
}
public static void main(String[] args) {
System.out.println(numbers(4));
}
}
With this I can get the correct answer for fairly big stock sizes. With a stock size of 10^6 the code completes in ~2 seconds, and with a stock of 10^7 numbers it takes a whole 27 seconds. This is not good enough, since I'm looking for a solution that can handle stock sizes of as big as 10^16, so I probably need a O(log(n)) solution.
This is a homework like assignment, so I didn't come here without wrestling with this pickle for quite some time. I have failed to come up with anything similiar by googling, and wolfram alpha doesn't recognize any kind of pattern this gives.
What I have concluded so far is that ones will allways run out first. I have no proof, but it is so.
Can anyone come up with any piece of advice? Thanks a lot.
EDIT:
I have come up with and implemented an efficient way of finding the cost of numbers 1...n thanks to btilly's pointers (see his post and comments below. also marked as a solution). I will elaborate this further after I have implemented the binary search for finding the last number you can write with the given stock later today.
EDIT 2: The Solution
I had completely forgotten about this post, so my apologies for not editing in my solution earlier. I won't copy the actual implementation, though.
My code for finding the cost of a number does the following:
First, let us choose a number, e.g. 9999. Now we will get the cost by summing the cost of each tens of digits like so:
9 9 9 9
^ ^ ^ ^
^ ^ ^ roof(9999 / 10^1) * 10^0 = 1000
^ ^ roof(9999 / 10^2) * 10^1 = 1000
^ roof(9999 / 10^3) * 10^2 = 1000
roof(9999 / 10^4) * 10^3 = 1000
Thus the cost for 9999 is 4000.
the same for 256:
2 5 6
^ ^ ^
^ ^ roof(256 / 10^1) * 10^0 = 26
^ roof(256 / 10^2) * 10^1 = 30
roof(256 / 10^3) * 10^2 = 100
Thus the cost for 256 is 156.
Implementing with this idea would make the program work only with numbers that have no digits 1 or 0, which is why further logic is needed. Let's call the method explained above C(n, d), where n is the number for which we are getting the cost for, and d is the d'th digit from n that we are currently working with. Let's also define a method D(n, d) that will return the d'th digit from n. Then we will apply the following logic:
sum = C(n, d)
if D(n, d) is 1:
for each k < d, k >= 0 :
sum -= ( 9 - D(n, k) ) * 10^(k-1);
else if D(n, d) is 0:
sum -= 10^(d-1)
With this the program will calculate the correct cost for a number efficiently. After this we simply apply a binary search for finding the number with the correct cost.
Step 1. Write an efficient function to calculate how much stock needs to be used to write all of the numbers up to N. (Hint: calculate everything that was used to write out the numbers in the last digit with a formula, and then use recursion to calculate everything that was used in the other digits.)
Step 2. Do a binary search to find the last number you can write with your amount of stock.
We can calculate the answer directly. A recursive formula can determine how much stock is needed to get from 1 to numbers that are powers of ten minus 1:
f(n, power, target){
if (power == target)
return 10 * n + power;
else
return f(10 * n + power, power * 10, target);
}
f(0,1,1) = 1 // a stock of 1 is needed for the numbers from 1 to 9
f(0,1,10) = 20 // a stock of 20 is needed for the numbers from 1 to 99
f(0,1,100) = 300 // a stock of 300 is needed for the numbers from 1 to 999
f(0,1,1000) = 4000 // a stock of 4000 is needed for the numbers from 1 to 9999
Where it gets complicated is accounting for the extra 1's needed when our calculation lands after the first multiple of any of the above coefficients; for example, on the second multiple of 10 (11-19) we need an extra 1 for each number.
JavaScript code:
function f(stock){
var cs = [0];
var p = 1;
function makeCoefficients(n,i){
n = 10*n + p;
if (n > stock){
return;
} else {
cs.push(n);
p *= 10;
makeCoefficients(n,i*10);
}
}
makeCoefficients(0,1);
var result = -1;
var numSndMul = 0;
var c;
while (stock > 0){
if (cs.length == 0){
return result;
}
c = cs.pop();
var mul = c + p * numSndMul;
if (stock >= mul){
stock -= mul;
result += p;
numSndMul++;
if (stock == 0){
return result;
}
}
var sndMul = c + p * numSndMul;
if (stock >= sndMul){
stock -= sndMul;
result += p;
numSndMul--;
if (stock == 0){
return result;
}
var numMul = Math.floor(stock / mul);
stock -= numMul * mul;
result += numMul * p;
}
p = Math.floor(p/10);
}
return result;
}
Output:
console.log(f(600));
1180
console.log(f(17654321));
16031415
console.log(f(2147483647));
1633388154

Linear Recurrence for very large n

I was trying to solve this problem on SPOJ (http://www.spoj.pl/problems/REC/)
F(n) = a*F(n-1) + b where we have to find F(n) Mod (m)
where
0 <= a, b, n <= 10^100
1 <= M <= 100000
F(0)=1
I am trying to solve it with BigInteger in JAVA but if I run a loop from 0 to n its getting TLE. How could I solve this problem? Can anyone give some hint? Don't post the solution. I want hint on how to solve it efficiently.
Note that the pattern of residues mod (m) should have a repeating pattern in a linear recurrence, and with length <= m by the pigeonhole principle. You need only calculate the first m entries, then figure out which of those entries will apply to F(n) for the actual value of n.
It also helps to solve a simpler problem. Let's pick really small values, say a=2, b=1, m=5, n=1000.
F(0) = 1
F(1) = 2*F(0) + 1 = 2*1 + 1 = 3 -> 3 Mod 5 = 3
F(2) = 2*F(1) + 1 = 2*3 + 1 = 7 -> 7 Mod 5 = 2
F(3) = 2*F(2) + 1 = 2*7 + 1 = 15 -> 15 Mod 5 = 0
F(4) = 2*F(3) + 1 = 2*15 + 1 = 31 -> 31 Mod 5 = 1
F(5) = 2*F(4) + 1 = 2*31 + 1 = 63 -> 63 Mod 5 = 3
etc.
Notice that the residues are [1, 3, 2, 0, 1, 3, ...], which will repeat forever. So from this example, how would you determine F(1000) Mod 5 without looping all the way to the 1000th entry?
First, I'll tell you how to solve a simpler problem. Suppose that b is zero. Then you just need to calculate an mod M. Instead of multiplying n-1 times, use a divide-and-conquer technique:
// Requires n >= 0 and M > 0.
int modularPower(int a, int n, int M) {
if (n == 0)
return 1;
int result = modularPower(a, n / 2, M);
result = (result * result) % M;
if (n % 2 != 0)
result = (result * a) % M;
return result;
}
So you can calculate an in terms of afloor(n/2), then square that, and multiply by a again if n is odd.
To solve your problem, first define the function f(x) = (a x + b) (mod M). You need to calculate fn(1), which is applying f n times to the initial value 1. So you can use divide-and-conquer like the previous problem. Luckily, the composition of two linear functions is also linear. You can represent a linear function by three integers (the two constants and the modulus). Write a function that takes a linear function and an exponent and returns the function composed that many times.

Optimizing digit <= 2 algorithm (similar to Project Euler 303)

I'm creating a program to solve Project Euler Problem 303
My method to find f(n) is barely short of brute force:
static BigInteger findFn(int n){
Long Fn = new Long(n);
String test = Fn.toString();
Long multiplier = new Long("1");
long counter = 0;
boolean done = false;
BigInteger fn = new BigInteger("0");
while(!done){
counter = 0;
BigInteger tempOne = new BigInteger(multiplier.toString());
BigInteger tempTwo = new BigInteger(Fn.toString());
BigInteger product = tempOne.multiply(tempTwo);
test = product.toString();
for(int i = 0; i < test.toString().length(); i++){
if(Character.getNumericValue(test.toString().charAt(i)) <= 2){
counter++;
}else{
//Is it better to set done = true here as opposed to breaking?
break; //breaks if it encounters any number in the multiple >2.
}
}
if(counter == test.length()){
fn = product;
done = true;
break;
}
multiplier++;
}
return fn;
}
It works well on most numbers, but there are a few (usually those that end in 9) that it just gets stuck on.
I think that the BigIntegers slow it down, so firstly, is there anywhere I've used a BigInteger where it isn't necessary?
Secondly, there has to be either an alternate method or some sort of other trick to cut down on the number of loops that I haven't thought of.
Any thoughts to give me a push in the right direction?
Thanks!!
I'm thinking you could cut out 67% of your trials just by looking at the digit in the one's place in the tested number because if that doesn't go to 0, 1, or 2 then it doesn't matter what the rest go to.
Consider that if the number ends in a 1, then the number it is multiplied by must end with a 0, 1, or 2 in order for the last digit of the result to be <= 2. So you test 1 then 2, and if those don't work then you test 10, 11, 12, then 20, 21, 22. So if the test number ends in a 1, you've now cut down your trials by 70%.
For XXX2, the multiplier would have to end in 0, 1, 5, or 6. That removes 60%. You can continue for 3-9.
What about trying the other way?
I have solved this problem by generating numbers that are composed of 0, 1 and 2 from smallest to bigger and looking at whom this number is the multiple of. Moreover, I have used the pattern for 9, 99, etc. (btw, you don't need BigInteger other than them. Since you will precompute them, get rid of BigInteger) but I found their values like your bruteforce method by incrementing in the multiples of interested number as pointed out before. Result popped out in around 6 seconds. If you want to see my solution, here it is.
test is a string, so there's no need to call toString() on it. Not a big improvement, but it makes the code a little cleaner.
Just off the top of my head here's an algorithm that would avoid BigInteger altogether.
For each multiplier
Set carry = 0
Set multiple = ""
Iterate through the digits of the multiplier from right to left
Set temp = digit * n + carry
if (right-most digit of temp > 2)
break and go to next multiplier
else
Set carry = temp / 10 // drop last digit and carry result
This basically does a long multiplication with the opportunity to break out of it as soon as a digit > 2 is found. Note that, to solve the problem, we don't actually need to get F(n), just F(n)/n which is the first multiplier for which the above digit iteration completes. Then just sum the least multiplier for each n.
Without actually trying it out, i'm pretty sure that this will run with just int values.
Update
So I've been playing with some code, and got it to work for 1 <= n <= 100. Looks like the multiplier for n = 999 > 2^31, so we need to use at least 64-bit values. Not sure what the multiplier is yet. My code has been running in LinqPad for over 21 minutes and has passed 3.2*10^9 with no result yet. Of course, there could be a problem with my code.
Try keeping around the results as you go forward. You can use these to make lowerbound guesses for their multiples.
Suppose the acceptable LCM for some X is Y, with Y = RX. Then you know that Y is also a lowerbound for all {X, 2X, 3X, 4X, ... (R-1)X}.
Not sure if the following idea would help:
Let P(N, M) = digits of M base 10 are (<= 2) and M is a multiple of N.
Let G(N) = Some M such that P(N, M).
Let F(N) = M such that P(N, M) and M is minimal.
Important observation: F(N) <= G(N).
Would want G(N) to be "reasonable" in that it isn't gratuitously large and is easy to calculate. You might be able to caculate it effectively using F(N') on smaller components N' of N (digits of N perhaps).
Knowing G(N) might be extremely useful...
Perhaps you can work backwards with it.
Perhaps you can perform some sort of binary search with it.
If this technique is at all useful, I imagine the hard math would be to find G(N). The rest would probably be some clever computer science technique.
To reduce the number of iterations you may increment the trial product by 1 instead of incrementing the trial multiplier by 1. Then you check whether or not the trial product is divisible by f()'s argument. This will enable you to get to bigger values quicker because you can skip digit values 4 through 9 in the product when adding 1.
The below C code completes in under 5 minutes on a 2.4 GHz PC:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include <time.h>
typedef unsigned uint;
typedef unsigned char uint8;
typedef unsigned long long uint64;
uint64 f(uint n, uint64* multiplier)
{
uint8 carry, digits[20]; // 20 digits max for 64-bit values
uint digcnt = 1, i;
uint64 result;
assert(n > 0);
#if 0
// short cut:
//
// f(9) = 12222 = 9 * 1358
// f(99) = 1122222222 = 99 * 11335578
// f(999) = 111222222222222 = 999 * 111333555778
// f(9999) = 11112222222222222222 = 9999 * 1111333355557778
if (n == 9999)
{
*multiplier = 11112222222222222222ULL / 9999;
return 11112222222222222222ULL;
}
#endif
memset(digits, 0, sizeof(digits));
for (;;)
{
carry = 1;
for (i = 0; carry; i++)
{
assert(i < sizeof(digits));
carry += digits[i];
digits[i] = carry % 3;
carry /= 3;
}
if (i >= digcnt) digcnt = i;
result = 0;
for (i = 0; i < digcnt; i++)
result = result * 10 + digits[digcnt - 1 - i];
if (result % n == 0)
{
*multiplier = result / n;
break;
}
}
return result;
}
int main(void)
{
uint i;
uint64 sum = 0, product, multiplier;
time_t t;
char* p;
for (i = 1; i <= 10000; i++)
{
product = f(i, &multiplier);
printf("%s ", ((time(&t), p = ctime(&t)), p[strlen(p) - 1] = '\0', p));
printf("f(%u) = %llu = %u * %llu\n", i, product, i, multiplier);
sum += multiplier;
}
printf("%s ", ((time(&t), p = ctime(&t)), p[strlen(p) - 1] = '\0', p));
printf("sum(f(n)/n) = %llu\n", sum);
return 0;
}
Output:
Mon Jan 9 12:18:22 2012 f(1) = 1 = 1 * 1
Mon Jan 9 12:18:22 2012 f(2) = 2 = 2 * 1
Mon Jan 9 12:18:22 2012 f(3) = 12 = 3 * 4
Mon Jan 9 12:18:22 2012 f(4) = 12 = 4 * 3
Mon Jan 9 12:18:22 2012 f(5) = 10 = 5 * 2
Mon Jan 9 12:18:22 2012 f(6) = 12 = 6 * 2
Mon Jan 9 12:18:22 2012 f(7) = 21 = 7 * 3
Mon Jan 9 12:18:22 2012 f(8) = 112 = 8 * 14
Mon Jan 9 12:18:22 2012 f(9) = 12222 = 9 * 1358
...
Mon Jan 9 12:18:39 2012 f(9998) = 111122211112 = 9998 * 11114444
Mon Jan 9 12:22:50 2012 f(9999) = 11112222222222222222 = 9999 * 1111333355557778
Mon Jan 9 12:22:50 2012 f(10000) = 10000 = 10000 * 1
Mon Jan 9 12:22:50 2012 sum(f(n)/n) = 1111981904675169
If you change #if 0 to #if 1 and enable the short cut mentioned in a comment by Peter Lawrey, it will complete in just about 1 minute.
Here's my contribution for this interesting problem. Pardon me for using Java and BigInteger but based on my loose testing it wasn't such a blocker after all (calculating sum [1, 100] takes less than a second and sum [1, 10000] roughly 4,5mins on my 2.4 dual core). And out of those 4+ mins around 4mins are spent on f(9999). Quite a surprise.
import java.math.BigInteger;
public class Main {
public static void main(String args[]) {
BigInteger result = BigInteger.ZERO;
for (int i = 1; i <= 10000; ++i) {
BigInteger r = f(BigInteger.valueOf(i));
System.out.println("i=" + i + " r=" + r);
result = result.add(r.divide(BigInteger.valueOf(i)));
}
System.out.println("result=" + result);
}
// Find smallest x * value which consists only of numbers {0, 1, 2}.
private static BigInteger f(BigInteger value) {
BigInteger retVal = value;
while (!check(retVal)) {
BigInteger remainder = remainder(retVal);
BigInteger mult = remainder.subtract(retVal.remainder(remainder))
.divide(value);
retVal = retVal.add(value.multiply(mult.max(BigInteger.ONE)));
}
return retVal;
}
// Find highest remainder for given value so that value % retVal =
// XYYYYY.. Where X > 2 and 0 <= Y <= 9.
private static BigInteger remainder(BigInteger value) {
BigInteger curVal = BigInteger.TEN;
BigInteger retVal = BigInteger.TEN;
while (value.compareTo(BigInteger.TEN) >= 0) {
curVal = curVal.multiply(BigInteger.TEN);
value = value.divide(BigInteger.TEN);
if (value.remainder(BigInteger.TEN).intValue() > 2) {
retVal = curVal;
}
}
return retVal;
}
// Check if given value contains only 0, 1 and 2.
private static boolean check(BigInteger value) {
do {
if (value.remainder(BigInteger.TEN).intValue() > 2) {
return false;
}
value = value.divide(BigInteger.TEN);
} while (value.compareTo(BigInteger.ZERO) == 1);
return true;
}
}

Categories

Resources