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 C++14 (judge verdict: Accepted)

#include<bits/stdc++.h>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/numeric/interval.hpp>
#include <boost/numeric/interval/io.hpp>
using namespace::std;
namespace mp = boost::multiprecision;
typedef mp::number<mp::cpp_dec_float<32,int64_t>> cfloat;
typedef mp::cpp_int cint;
typedef long long lint;
typedef long long ll;
typedef long double ldouble;
typedef vector<lint> vec;
typedef vector<vector<lint>> mat;
typedef vector<vector<vector<lint>>> mat3;
#define rep(i, n) for(lint i = 0; i < (lint)(n); i++)
#define irep(i) for(lint i = 0;; i++)
#define irep1(i) for(lint i = 1;; i++)
#define irep2(i) for(lint i = 2;; i++)
#define rrep(i, n) for(lint i = (lint)(n-1); i >-1; i--)
#define rrepi(i,a,b) for(lint i = (lint)(b-1); i >a-1; i--)
#define repi(i,a,b) for(lint i=lint(a);i<lint(b);i++)
#define rep2(i,a,b,c) for(lint i=lint(a);i>lint(b);i+=c)
#define all(x) (x).begin(),(x).end()
#define sl(c) (('a')<=(c)&&(c)<=('z'))
#define ll(c) (('A')<=(c)&&(c)<=('Z'))
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
#define PI 3.141592653589793
#define cout (cout<<fixed<<setprecision(15))
#define makeupper(t) (transform(all(t),t.begin(),::toupper))
#define makelower(t) (transform(all(t),t.begin(),::tolower))
#define dist(x1,y1,x2,y2) (pow(pow(x2-x1,2)+pow(y2-y1,2),0.5))
#define NEXT_LINE string junk; getline(cin, junk);
#define output(v) do{rep(i,v.size())cout<<(i?" ":"")<<v[i];cout<<"\n";}while(0)
#define output2(v) rep(i,v.size()){rep(j,v[i].size()){cout<<(j?" ":"")<<v[i][j];}cout<<"\n";}
#define INF 1LL<<40
#define IINF 1<<30
#define LINF 9223372036854775807
#define MOD 1000000007
vector<lint> dx={-1,1,0,0,1,1,-1,-1};
vector<lint> dy={0,0,-1,1,1,-1,1,-1};
vector<lint> operator+(const vector<lint>& v1,const vector<lint>& v2){
    vector<lint> v(v1.size()+v2.size(),0);
    rep(i,v1.size())v[i]=v1[i];
    rep(i,v2.size())v[i+v1.size()]=v2[i];
    return v;
}
inline lint sum(vector<lint> v){
    lint sum=0;
    rep(i,v.size())sum+=v[i];
    return sum;
}
inline string replace(string str, string before, std::string after) {
	string::size_type  Pos(str.find(before));
	while (Pos != std::string::npos) {
		str.replace(Pos, before.length(), after);
		Pos = str.find(before, Pos + after.length());
	}
	return str;
}
inline vector<string> split(string s, string delim) {
	vector<string> elems;
	s=replace(s, "#", "HASH");
	s=replace(s, delim,"#");
	stringstream ss(s);
	string item;
	while (getline(ss, item, '#')) {
		elems.push_back(replace(item, "HASH", "#"));
	}
	return elems;
}
inline vector<int> cross(vector<int> a, vector<int> b) {
    return { a[1] * b[2] - a[2] * b[1],a[2] * b[0] - a[0] * b[2],a[0] * b[1] - a[1] * b[0] };
}
inline lint GCD(lint a,lint b){return b?GCD(b,a%b):a;}
inline vector<lint> primeList(lint n) {
    vector<bool> p(n+1);
    vector<lint> list;
    repi(i,1, n+1)p[i] = true;
    repi(i,2,sqrt(n)+1) {
        if (p[i]) {
            repi(j,2,n/i+1) {
                p[i*j] = false;
            }
        }
    }
    repi(i, 2, n+1)if (p[i])list.push_back(i);
    return list;
}
inline set<lint> primeSet(lint n) {
    vector<bool> p(n+1);
    set<lint> set;
    repi(i,1, n+1)p[i] = true;
    repi(i,2,sqrt(n)+1) {
        if (p[i]) {
            repi(j,2,n/i+1) {
                p[i*j] = false;
            }
        }
    }
    repi(i, 2, n+1)if (p[i])set.insert(i);
    return set;
}
inline bool isPrime(int num){
    if (num < 2) return false;
    else if (num == 2) return true;
    else if (num % 2 == 0) return false;
    double sqrtNum = sqrt(num);
    for (int i = 3; i <= sqrtNum; i += 2){
        if (num % i == 0)return false;
    }
    return true;
}
inline lint max(vector<lint> num){
    lint M=num[0];
    rep(i,num.size())M=max(M,num[i]);
    return M;
}
inline lint min(vector<lint> num){
    lint M=num[0];
    rep(i,num.size())M=min(M,num[i]);
    return M;
}
inline cint cmax(vector<cint> num){
    cint M=num[0];
    rep(i,num.size())if(M<num[i])M=num[i];
    return M;
}
inline cint cmin(vector<cint> num){
    cint M=num[0];
    rep(i,num.size())if(M>num[i])M=num[i];
    return M;
}
inline lint signal(lint val){
    if(val==0)return 0;
    else return val/abs(val);
}
struct IVector2{
    lint x,y;
};
bool operator< (const IVector2 &s, const IVector2 &t){
        return s.x==t.x?s.y<t.y:s.x<t.x;
};
bool operator> (const IVector2 &s, const IVector2 &t){
        return s.x==t.x?s.y>t.y:s.x>t.x;
};
struct IVector3{
    lint x,y,z;
};
struct IVector4{
    lint x,y,z,w;
};
struct UF{
    public:
    vector<lint> par;
    vector<lint> rank;
    lint _s;
    UF(lint size){
        _s=size;
        par.resize(size);
        rep(i,size)par[i]=i;
        rank.resize(size,0);
    }
    bool unite(lint x,lint y){
        x=root(x);y=root(y);
        if(x==y)return false;
        if(rank[x]<rank[y])swap(x,y);
        if(rank[x]==rank[y])rank[x]++;
        par[y]=x;
        _s--;
        return true;
    }
    lint root(lint x){
        while(x!=par[x]){
            x=par[x]=par[par[x]];
        }
        return x;
    }
    bool same(lint x, lint y) {
        return root(x) == root(y);
    }
    lint size(){
        return _s;
    }
};
class Fraction{
    public:
    lint p,q;
    Fraction(lint _p,lint _q){
        lint x=GCD(_p,_q);
        p=_p/x;
        q=_q/x;
    }
    void about_minutes(Fraction& n){
        lint x=GCD(n.p,n.q);
        n.p/=x;
        n.q/=x;
    }
    Fraction operator+(const Fraction rhs) const noexcept {
        return Fraction(*this) += rhs;
    }
    Fraction operator-(const Fraction rhs) const noexcept {
        return Fraction(*this) -= rhs;
    }
    Fraction operator*(const Fraction rhs) const noexcept {
        return Fraction(*this) *= rhs;
    }
    Fraction operator/(const Fraction rhs) const noexcept {
        return Fraction(*this) /= rhs;
    }
    Fraction &operator+=(const Fraction rhs) noexcept {
        lint x=GCD(q,rhs.q);
        p=(p*rhs.q+q*rhs.p)/x;
        q=q*rhs.q/x;
        about_minutes(*this);
        return *this;
    }
    Fraction &operator-=(const Fraction rhs) noexcept {
        lint x=GCD(q,rhs.q);
        p=(p*rhs.q-q*rhs.p)/x;
        q=q*rhs.q/x;
        about_minutes(*this);
        return *this;
    }
    Fraction &operator*=(const Fraction rhs) noexcept {
        p*=rhs.p;
        q*=rhs.q;
        lint x=GCD(p,q);
        p/=x;
        q/=x;
        return *this;
    }
    Fraction &operator/=(const Fraction rhs) noexcept {
        p*=rhs.q;
        q*=rhs.p;
        lint x=GCD(p,q);
        p/=x;
        q/=x;
        return *this;
    }
    bool operator<(const int rhs) noexcept {
        return p<q*rhs;
    }
    bool operator>(const int rhs) noexcept {
        return p>q*rhs;
    }
    bool operator<(const Fraction rhs) noexcept {
        return p*rhs.q<q*rhs.p;
    }
    bool operator>(const Fraction rhs) noexcept {
        return p*rhs.q>q*rhs.p;
    }
    bool operator<=(const int rhs) noexcept {
        return p<=q*rhs;
    }
    bool operator>=(const int rhs) noexcept {
        return p>=q*rhs;
    }
    bool operator<=(const Fraction rhs) noexcept {
        return p*rhs.q<=q*rhs.p;
    }
    bool operator>=(const Fraction rhs) noexcept {
        return p*rhs.q>=q*rhs.p;
    }
    lint floor(){
        return std::floor(p*1./q);
    }
    Fraction reverse(){
        return Fraction(q,p);
    }
};
ostream& operator<<(ostream& lhs, const Fraction& rhs) noexcept {
    lhs << rhs.p<<"/"<<rhs.q;
    return lhs;
}
int main(){
    while(1){
        lint p,q,A,n;
        cin>>p>>q>>A>>n;
        if(p==0&&q==0&&A==0&&n==0)break;
        stack<tuple<lint,lint,lint,lint,lint>> s;
        s.push(make_tuple(p,q,1,n,1));
        lint cnt=0;
        while(!s.empty()){
            auto d=s.top();
            s.pop();
            vec a={get<0>(d),get<1>(d),get<2>(d),get<3>(d),get<4>(d)};
            lint x=GCD(a[0],a[1]);
            a[0]/=x;
            a[1]/=x;
            if(a[0]==0){
                cnt++;
                continue;
            }
            for(int i=0;i*a[0]<=a[1]*a[3];i++){
                if(a[1]>i*a[0]||a[4]>i)continue;
                if(A>=a[2]*i)s.push(make_tuple(a[0]*i-a[1],a[1]*i,a[2]*i,a[3]-1,i));
            }
        }
        cout<<cnt<<endl;
    }
}