Problem:
Problem C: Unit Fraction Partition

A fraction whose numerator is 1
and whose denominator is a positive integer
is called a unit fraction.
A representation of a positive rational number
p/q
as the sum of finitely many unit fractions is called a partition of
p/q
into unit fractions.
For example,
1/2 + 1/6
is a partition of
2/3
into unit fractions.
The difference in the order of addition is disregarded.
For example, we do not distinguish
1/6 + 1/2
from
1/2 + 1/6.

For given four positive integers
p,
q,
a, and
n,
count the number
of partitions of
p/q
into unit fractions satisfying the following two conditions.

The partition is the sum of at most
n
many unit fractions.

The product of the denominators of the unit fractions in the
partition is less than or equal to
a.

For example, if
(p,q,a,n) = (2,3,120,3),
you should report 4 since

enumerates all of the valid partitions.

Input

The input is a sequence of at most 1000 data sets followed by a terminator.

A data set is a line containing four positive integers
p,
q,
a, and
n
satisfying
p,q <= 800,
a <= 12000
and
n <= 7.
The integers are separated by a space.

The terminator is composed of just one line
which contains four zeros separated by a space.
It is not a part of the input data but a mark for the end of the input.

Output

The output should be composed of lines
each of which contains a single integer.
No other characters should appear in the output.

The output integer corresponding to a data set
p,
q,
a,
n
should be the number of all partitions of
p/q
into at most
n
many unit fractions such that the product of the denominators of the
unit fractions is less than or equal to
a.

Sample Input

2 3 120 3
2 3 300 3
2 3 299 3
2 3 12 3
2 3 12000 7
54 795 12000 7
2 3 300 1
2 1 200 5
2 4 54 2
0 0 0 0

Output for the Sample Input

4
7
6
2
42
1
0
9
3

Solution in JAVA (judge verdict: Time Limit Exceeded)

import java.io.IOException;
import java.util.InputMismatchException;
import java.util.TreeMap;

public class Main {
	int a, n;
	Fraction order;
	TreeMap<D, Integer> set;

	class Fraction implements Comparable<Fraction>{
		long numerator;
		long denominator;

		Fraction(long numerator, long denominator) {
			this.numerator = numerator;
			this.denominator = denominator;
			reduce();
		}

		Fraction(long k) {
			this.numerator = k;
			this.denominator = 1;
		}

		Fraction add(Fraction x) {
			long a = this.denominator;
			long b = this.numerator;
			long c = x.denominator;
			long d = x.numerator;
			Fraction res = new Fraction(b*c + a*d, a*c);
			res.reduce();
			return res;
		}

		Fraction sub(Fraction x) {
			long a = this.denominator;
			long b = this.numerator;
			long c = x.denominator;
			long d = x.numerator;
			Fraction res = new Fraction(b*c - a*d, a*c);
			res.reduce();
			return res;
		}

		Fraction multiple(Fraction x) {
			long a = this.denominator;
			long b = this.numerator;
			long c = x.denominator;
			long d = x.numerator;
			Fraction res = new Fraction(b*d, a*c);
			res.reduce();
			return res;
		}

		Fraction devide(Fraction x) {
			long a = this.denominator;
			long b = this.numerator;
			long c = x.denominator;
			long d = x.numerator;
			Fraction res = new Fraction(b*c, a*d);
			res.reduce();
			return res;
		}

		void reduce() {
			long gcd = gcd(numerator, denominator);
			this.numerator /= gcd;
			this.denominator /= gcd;
			if (this.denominator < 0) {
				this.numerator *= -1;
				this.denominator *= -1;
			}
		}

		long gcd(long a,long b) {
			a = Math.abs(a);
			b = Math.abs(b);
			while (a != 0 && b != 0) {
				if (a > b) a %= b;
				else b %= a;
			}
			if (a == 0) return b;
			return a;
		}

		@Override
		public int compareTo(Fraction o) {
			long a = this.numerator;
			long b = this.denominator;
			long c = o.numerator;
			long d = o.denominator;
			if (a*d - b*c > 0) return 1;
			if (a*d - b*c < 0) return -1;
			return 0;
		}

		@Override
		public String toString() {
			String res = "" + numerator;
			if (denominator != 1) res += "/" + denominator;
			return res;
		}
	}

	class D implements Comparable<D>{
		Fraction f;
		int pre;
		int pi;
		int k;

		D(Fraction f, int pre, int pi, int k) {
			this.f = f;
			this.pre = pre;
			this.pi = pi;
			this.k = k;
		}

		@Override
		public int compareTo(D o) {
			if (this.f.compareTo(o.f) != 0)
				return this.f.compareTo(o.f);
			if (this.pre != o.pre)
				return this.pre - o.pre;
			if (this.pi != o.pi)
				return this.pi - o.pi;
			return this.k - o.k;
		}
	}

	int bt(Fraction pre, Fraction sum, int k, int pi) {
		int cmp = sum.compareTo(order);
		if (cmp > 0)
			return 0;
		if (cmp == 0)
			return 1;
		if (n <= k)
			return 0;

		int res = 0;
		int t = (int)pre.denominator;
		for (int i = t; pi*i <= a; i++) {
			Fraction nf = new Fraction(1, i);
			Fraction nsum = sum.add(nf);
			res += bt(nf, nsum, k + 1, pi*i);
		}
		return res;
	}

	int dp(D d) {
		if (set.containsKey(d)) {
			return set.get(d);
		}

		Fraction f = d.f;
		int p = (int)f.numerator;
		int q = (int)f.denominator;
		int pre = d.pre;
		int pi = d.pi;
		int k = d.k;
		if (f.numerator == 0) {
			return 1;
		}
		if (n <= k || a < pi) {
			return 0;
		}

		int res = 0;
		for (int i = pre; q <= p * i; i--) {
			int np = p*i - q;
			int nq = q*i;
			res += dp(new D(new Fraction(np, nq), i, pi*i, k + 1));
		}
		set.put(d, res);
		return res;
	}

	void run() {
		MyScanner sc = new MyScanner();

		while (true) {
			int p = sc.nextInt();
			int q = sc.nextInt();
			a = sc.nextInt();
			n = sc.nextInt();
			if ((p | q | a | n) == 0) {
				break;
			}
			set = new TreeMap<D, Integer>();

//			System.out.println(dp(new D(new Fraction(p, q), a, 1, 0)));
			order = new Fraction(p, q);
			System.out.println(bt(new Fraction(1), new Fraction(0), 0, 1));
		}
	}

	public static void main(String[] args) {
		new Main().run();
	}

	public void mapDebug(int[][] a) {
		System.out.println("--------map display---------");
		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a[i].length; j++) {
				System.out.printf("%3d ", a[i][j]);
			}
			System.out.println();
		}
		System.out.println("----------------------------" + '\n');
	}

	class MyScanner {
		int read() {
			try {
				return System.in.read();
			} catch (IOException e) {
				throw new InputMismatchException();
			}
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		int[] nextIntArray(int n) {
			int[] array = new int[n];
			for (int i = 0; i < n; i++)
				array[i] = nextInt();
			return array;
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		long[] nextLongArray(int n) {
			long[] array = new long[n];
			for (int i = 0; i < n; i++)
				array[i] = nextLong();
			return array;
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		double[] nextDoubleArray(int n) {
			double[] array = new double[n];
			for (int i = 0; i < n; i++)
				array[i] = nextDouble();
			return array;
		}

		String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		String[] nextStringArray(int n) {
			String[] array = new String[n];
			for (int i = 0; i < n; i++)
				array[i] = next();

			return array;
		}

		String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}
}