import java.util.BitSet; import java.util.Scanner; /** * Solution to the Hardy's Taxi problem. * "A study in efficiency" * n=1: 1729, and n=43: 994688 (took ~1 min to run to find all < 1M) * n=133: 8,131,968 (took <1 sec using more efficient method) * n=275: 33,108,264 (ditto) * n=499: 106,243,219 (~2 secs) * * @author Matt Boutell. * Created Apr 11, 2008. */ public class Hardy { private static int maxCube = 0; private static int[] cubes; private static byte[] counts; /** * Start here. * * @param args */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); //int n = 200; // size of BitSet increases in multiples of 64. //BitSet b = new BitSet(129); //System.out.println(b.size()); //for (int i = 0; i < b.size(); i++) { //b.set(i, i % 5 == 0); //} //System.out.println(b); //System.exit(0); // Precompute cues // Runs out of heap space if we make it too large. // 97 = max with n-by-5 2D array of ints, gives n = 39 // 110 = max with n-by-1 2D array of ints, gives n = 53 // 197 = max with 1D array of ints, gives n = 133 // 249 = max with 1D array of shorts, gives n = 197 // 313 = max with 1D array of bytes, gives n = 275 // 498 = max with 2 BitSets , gives n = 499 Hardy.maxCube = 498; cubes = new int[Hardy.maxCube+1]; for (int i = 0; i < Hardy.maxCube; i++) { cubes[i] = i*i*i; } //method1(n); //method2(n); method3(n); } /** * A more efficient way of finding the nth integer that * can be expressed as the sum of 2 cubes in at least 2 different ways. * This uses a BitSet to store which ones have cubes * * @param n */ private static void method3(int n) { int upperBound = 2 * Hardy.maxCube * Hardy.maxCube * Hardy.maxCube; // System.out.println("UB: " + upperBound); int nFound = 0; BitSet found1 = new BitSet(upperBound); BitSet found2 = new BitSet(upperBound); int maxFactor = (int)Math.floor(Math.pow(upperBound/2, 1.0/3.0)); // System.out.println("MF:" + maxFactor); for (int i = 1; i <= maxFactor; i++) { for (int j = i; j <= maxFactor; j++) { int num = cubes[i] + cubes[j]; if (num < upperBound) { if (!found1.get(num)) { found1.set(num); } else if (found1.get(num) && !found2.get(num)) { found2.set(num); } else { nFound++; if (nFound >= n) { maxFactor = (int)Math.floor(Math.pow(num/2, 1.0/3.0)); } } } } } int count = 1; int[] countAndFactors = new int[5]; int i; for (i = 0; i< found2.size() && count <= n; i++) { if (found2.get(i)) { //System.out.println(count); countAndFactors = nWaysToMake2Cubes(i); count++; } } if (count >= n) { System.out.printf("%d = %d^3 + %d^3 = %d^3 + %d^3\n", i-1, countAndFactors[1], countAndFactors[2], countAndFactors[3], countAndFactors[4]); } } /** * A somewhat efficient way of finding the nth integer that * can be expressed as the sum of 2 cubes in at least 2 different ways. * * @param n */ private static void method2(int n) { int upperBound = 2 * Hardy.maxCube * Hardy.maxCube * Hardy.maxCube; System.out.println("UB: " + upperBound); int nFound = 0; counts = new byte[upperBound]; //int[][] counts = new int[upperBound][5]; int maxFactor = (int)Math.floor(Math.pow(upperBound/2, 1.0/3.0)); System.out.println("MF:" + maxFactor); for (int i = 1; i <= maxFactor; i++) { for (int j = i; j <= maxFactor; j++) { int num = cubes[i] + cubes[j]; if (num < upperBound) { counts[num]++; if (counts[num] < 3) { //counts[num][counts[num][0]*2-1] = i; //counts[num][counts[num][0]*2] = j; } if (counts[num] >= 2) { nFound++; //if (nFound >= n) { //maxFactor = (int)Math.floor(Math.pow(num/2, 1.0/3.0)); //} } } } } int count = 1; int[] countAndFactors = new int[5]; for (int i = 0; i< counts.length && count <= n; i++) { if (counts[i] >= 2) { System.out.println(count); countAndFactors = nWaysToMake2Cubes(i); count++; } } } /** * Finds the nth integer that can be expressed as the sum of 2 cubes * in at least 2 different ways. This is a brute-force method that * just iterates over numbers and checks them. * * @param n */ private static void method1(int n) { int count = 0; int i = 0; while (count < n) { if (2 == nWaysToMake2Cubes(i)[0]) { count++; System.out.println(count); } i++; } } private static int[] nWaysToMake2Cubes(int num) { int count = 0; double tol = 0.00001; int[] a = new int[2]; int[] b = new int[2]; int maxToLook = (int)Math.ceil(Math.pow(num/2, 1.0/3.0)); for (int aGuess = 1; aGuess < maxToLook; aGuess++) { // n - a^3. Does it = b^3? int diff = num - Hardy.cubes[aGuess]; double bGuess = Math.pow(diff, 1.0/3.0); int bGuessRounded = (int)(bGuess+0.5); //System.out.println(aGuess + " " + diff + " "); if (Math.abs(bGuess - bGuessRounded) < tol) { //it's a cube of an int a[count] = aGuess; b[count] = bGuessRounded; count++; } if (count == 2) break; } int[] countAndFactors = new int[5]; countAndFactors[0] = count; if (count > 1) { countAndFactors[1] = a[0]; countAndFactors[2] = b[0]; countAndFactors[3] = a[1]; countAndFactors[4] = b[1]; } return countAndFactors; } }