project euler 78

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);
		}

	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值