Problem 78
Coin partitions
Let p(n) represent the number of different ways in which n coins can be separated into piles. For example, five coins can separated into piles in exactly seven different ways, so p(5)=7.
OOOOO
OOOO O
OOO OO
OOO O O
OO OO O
OO O O O
O O O O O
Find the least value of n for which p(n) is divisible by one million.
硬币分拆
记p(n)是将n枚硬币分拆成堆的不同方式数。例如,五枚硬币有7种分拆成堆的不同方式,因此p(5)=7。
OOOOO
OOOO O
OOO OO
OOO O O
OO OO O
OO O O O
O O O O O
找出使p(n)能被一百万整除的最小n值。
package projecteuler;
import junit.framework.TestCase;
/**
* 五边形定理
* https://en.wikipedia.org/wiki/Partition_%28number_theory%29#Recurrence_formula;
* @author suc
*
*/
public class Prj78Ex extends TestCase {
public static final int LIMIT = 1000000;
public static final int COUNT = 100000;
static int N = COUNT + 1;
static int[] p = new int[N + 1];
public void testCoinPartitions() {
init();
for (int i = 0; i < N; i++) {
if(p[i] == 0){
System.out.println("p[" + i + "]==" + p[i]);
}
}
System.out.println();
System.out.println("p[5]=" + p[0]);
}
void init() {
p[0] = p[1] = 1;
for (int i = 2; i <= N; ++i) {
p[i] = 0;
int x = 1;
for (int k = 1, j = 1; x >= 0; ++k, j *= -1) {
x = i - (3 * k * k + k) / 2;
if (x >= 0) {
p[i] += p[x] * j;
}
x = i - (3 * k * k - k) / 2;
if (x >= 0) {
p[i] += p[x] * j;
}
if (p[i] >= LIMIT || p[i] < 0) {
p[i] = (p[i] % LIMIT + LIMIT) % LIMIT;
}
}
}
}
}
package projecteuler;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
public class Prj78 extends TestCase {
public static final int COUNT = 100;
/**
* https://en.wikipedia.org/wiki/Partition_(number_theory)#Partition_function;
*/
public void testCoinPartitions() {
int i = 2;
while (true) {
BigInteger num = PartitionFunction.p(i);
if (i % 1 == 0) {
System.out.println("iter=" + i + "," + num.toString());
}
if (num.divideAndRemainder(new BigInteger(Integer.toString(COUNT)))[1]
.equals(BigInteger.ZERO)) {
System.out.println("i=" + i);
return;
}
i++;
}
}
/**
* Counts the number of ways of representing n as a distinct sum of positive
* integers <= m.
*
* @param n
* number to sum to
* @param m
* restriction on the component numbers
* @return number of ways
*/
public static long p(final long n, final long m) {
if (n <= 1) {
// recursive stopping condition
return 1;
}
if (m > n) {
// using component numbers > n doesn't contribute any more
// ways to sum to n
return p(n, n);
}
long sum = 0;
for (long k = 1; k <= m; k++) {
sum = sum + p(n - k, k);
}
return sum;
}
/**
* Counts the number of ways of representing n as a distinct sum of positive
* integers.
*
* @param n
* number to sum to
* @return number of ways
*/
public static long p(final long n) {
return p(n, n);
}
public static class PartitionFunction {
static final private Map<String, BigInteger> cache = new HashMap<>();
/**
* Counts the number of ways of representing n as a distinct sum of
* positive integers <= m.
*
* @param n
* number to sum to
* @param m
* restriction on the component numbers
* @return number of ways
*/
public static BigInteger p(final long n, final long m) {
if (n <= 1) {
// recursive stopping condition
return BigInteger.ONE;
}
if (m > n) {
// using component numbers > n doesn't contribute any more
// ways to sum to n
return p(n, n);
}
String cacheKey = n + "," + m;
BigInteger sum = cache.get(cacheKey);
if (sum != null) {
return sum;
}
sum = BigInteger.ZERO;
for (long k = 1; k <= m; k++) {
sum = sum.add(p(n - k, k));
}
cache.put(cacheKey, sum);
return sum;
}
/**
* Counts the number of ways of representing n as a distinct sum of
* positive integers.
*
* @param n
* number to sum to
* @return number of ways
*/
public static BigInteger p(final long n) {
return p(n, n);
}
}
}