Problem p00712 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>

using namespace std;

int gcd(int p, int q) {
  if (p < q) {
    int t = p;
    p = q;
    q = t;
  }
  while (q != 0) {
    int t = p;
    p = q;
    q = t % q;
  }
  return p;
}

int pow2(int a, int b) {
  int e = a, p = 1;
  while (b != 0) {
    while ((b & 1) == 0) {
      b >>= 1;
      e *= e;
    }
    p *= e;
    b >>= 1, e *= e;
  }
  return p;
}

struct Frac {
  int p, q;
  Frac() {}
  Frac(int p, int q) {
    int d = gcd(p, q);
    p /= d, q /= d;
    this->p = p, this->q = q;
  }
  Frac(int n) : p(n), q(1) {}
  Frac operator+(const Frac rhs) const {
    return Frac(p * rhs.q + q * rhs.p, q * rhs.q);
  }
  bool operator<(const Frac rhs) const { return (p * rhs.q - q * rhs.p < 0); }
  bool operator==(const Frac rhs) const {
    return (!(*this < rhs) && !(rhs < *this));
  }
  int gauss() {
    if (p % q == 0) {
      return p;
    }
    return (p / q) + 1;
  }
};

int P, Q, A, N;

int ans(Frac tar, int m, int prod, int rest) {
  // printf("tar = %d/%d, m = %d, prod = %d, rest = %d\\n",
  //	 tar.p, tar.q, m, prod, rest);
  if (tar < 0) {
    return 0;
  }
  if (prod > A) {
    return 0;
  }
  if (tar == 0) {
    // printf("Found\\n");
    return 1;
  }
  if (rest == 0) {
    return 0;
  }
  int min_q;
  for (min_q = m;; min_q++) {
    if (Frac(1, min_q) < tar || Frac(1, min_q) == tar) {
      break;
    }
  }
  int sum = 0;
  for (int i = min_q;; i++) {
    if (prod * pow2(i, min(Frac(tar.p * i, tar.q).gauss(), rest)) > A) {
      break;
    }
    if (Frac(rest, i) < tar) {
      break;
    }
    sum += ans(tar + Frac(-1, i), i, prod * i, rest - 1);
  }
  return sum;
}

void solve() { printf("%d\\n", ans(Frac(P, Q), 1, 1, N)); }

int main() {
  while (scanf("%d %d %d %d", &P, &Q, &A, &N) == 4) {
    if (P == 0 && Q == 0 && A == 0 && N == 0) {
      break;
    }
    solve();
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>

using namespace std;

int gcd(int p, int q) {
  if (p < q) {
    int t = p;
    p = q;
    q = t;
  }
  while (q != 0) {
    int t = p;
    p = q;
    q = t % q;
  }
  return p;
}

int pow2(int a, int b) {
  int e = a, p = 1;
  while (b != 0) {
    while ((b & 1) == 0) {
      b >>= 1;
      e *= e;
    }
    p *= e;
    b >>= 1, e *= e;
  }
  return p;
}

struct Frac {
  int p, q;
  Frac() {}
  Frac(int p, int q) {
    int d = gcd(p, q);
    p /= d, q /= d;
    this->p = p, this->q = q;
  }
  Frac(int n) : p(n), q(1) {}
  Frac operator+(const Frac rhs) const {
    return Frac(p * rhs.q + q * rhs.p, q * rhs.q);
  }
  bool operator<(const Frac rhs) const { return (p * rhs.q - q * rhs.p < 0); }
  bool operator==(const Frac rhs) const {
    return (!(*this < rhs) && !(rhs < *this));
  }
  int gauss() {
    if (p % q == 0) {
      return p;
    }
    return (p / q) + 1;
  }
};

int P, Q, A, N;

int ans(Frac tar, int m, int prod, int rest) {
  // printf("tar = %d/%d, m = %d, prod = %d, rest = %d\\n",
  //	 tar.p, tar.q, m, prod, rest);
  if (tar < 0) {
    return 0;
  }
  if (prod > A) {
    return 0;
  }
  if (tar == 0) {
    // printf("Found\\n");
    return 1;
  }
  if (rest == 0) {
    return 0;
  }
  int min_q;
  for (min_q = m;; min_q++) {
    if (Frac(1, min_q) < tar || Frac(1, min_q) == tar) {
      break;
    }
  }
  int sum = 0;
  for (int i = min_q;; i++) {
    if (pow2(i, min(Frac(tar.p * i, tar.q).gauss(), rest)) > A) {
      break;
    }
    if (Frac(rest, i) < tar) {
      break;
    }
    sum += ans(tar + Frac(-1, i), i, prod * i, rest - 1);
  }
  return sum;
}

void solve() { printf("%d\\n", ans(Frac(P, Q), 1, 1, N)); }

int main() {
  while (scanf("%d %d %d %d", &P, &Q, &A, &N) == 4) {
    if (P == 0 && Q == 0 && A == 0 && N == 0) {
      break;
    }
    solve();
  }
  return 0;
}