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

#include <iostream>
#include <string>
#include <vector>

using namespace std;

long long fact[15];

vector<vector<int>> digits;

void search(vector<int> &v, int cur, int rest) {
  if (cur == 9) {
    v[cur] = rest;
    digits.push_back(v);
    return;
  }
  for (int i = 0; i <= rest; i++) {
    v[cur] = i;
    search(v, cur + 1, rest - i);
  }
}

long long perm(const vector<int> &v) {
  int sum = 0;
  for (int i = 0; i < 10; ++i)
    sum += v[i];
  long long res = fact[sum];
  for (int i = 0; i < 10; i++)
    res /= fact[v[i]];
  return res;
}

int main() {
  fact[0] = 1;
  for (int i = 1; i <= 14; i++)
    fact[i] = i * fact[i - 1];
  string S;
  while (cin >> S) {
    int n = S.size();
    digits.clear();
    vector<int> v(10, 0);
    search(v, 0, n);
    int sum = 0;
    long long prod = 1;
    for (int i = 0; i < n; i++) {
      sum += S[i] - '0';
      prod *= S[i] - '0' + 1;
    }
    long long res = 0;
    for (const vector<int> &dig : digits) {
      v = dig;
      int s = 0;
      long long p = 1;
      for (int i = 0; i < 10; i++) {
        s += i * v[i];
        for (int j = 0; j < v[i]; j++)
          p *= i + 1;
      }
      if (s < sum || (s == sum && p < prod)) {
        res += perm(v);
      } else if (s == sum && p == prod) {
        for (int i = 0; i < n; i++) {
          for (int j = 0; j < S[i] - '0'; j++) {
            if (v[j] == 0)
              continue;
            --v[j];
            res += perm(v);
            ++v[j];
          }
          if (v[S[i] - '0'] == 0)
            break;
          --v[S[i] - '0'];
        }
      }
    }
    cout << res << endl;
  }
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Number {
public:
  Number(long long l = 0) { setVal(l); }
  int sum, prod;
  long long val;
  void setVal(long long l) {
    sum = 0;
    prod = 1;
    val = l;
    while (l) {
      int m = l % 10;
      sum += m;
      prod *= m + 1;
      l /= 10;
    }
  }
  bool operator<(const Number &n) const {
    return sum != n.sum     ? sum < n.sum
           : prod != n.prod ? prod < n.prod
                            : val < n.val;
  }
};

long long calcSum(long long l) {
  long long res = 0;
  while (l) {
    res += l % 10;
    l /= 10;
  }
  return res;
}

long long calcProd(long long l) {
  long long res = 1;
  while (l) {
    res *= l % 10 + 1;
    l /= 10;
  }
  return res;
}

class Order {
public:
  long long v;
  void setVal(int t) { v = (calcSum(t) << 50) + (calcProd(t) << 25) + t; }
  long long getSum() const { return v >> 50; }
  long long getProd() const { return (v >> 25) % (1 << 25); }
  long long getVal() const { return v % (1 << 25); }
  bool operator<(const Order &o) const { return v < o.v; }
};

long long pow10(int p) {
  long long res = 1;
  for (int i = 0; i < p; i++)
    res *= 10;
  return res;
}

long long solve(long long L, long long upperB, const vector<Number> &va,
                const vector<Number> &vb) {
  int idxB = vb.size() - 1;
  long long res = 0;
  Number target(L);
  Number number;
  for (int i = 0; i < va.size(); i++) {
    while (idxB >= 0) {
      number.sum = va[i].sum + vb[idxB].sum;
      number.prod = va[i].prod * vb[idxB].prod;
      number.val = va[i].val * upperB + vb[idxB].val;
      if (number < target)
        break;
      --idxB;
    }
    res += idxB + 1;
  }
  return res;
}

bool isSmall(const Order &oA, const Order &oB, long long upperB, long long sum,
             long long prod, long long val) {
  long long s = oA.getSum() + oB.getSum();
  if (s != sum)
    return s < sum;
  long long p = oA.getProd() * oB.getProd();
  if (p != prod)
    return p < prod;
  long long v = oA.getVal() * upperB + oB.getVal();
  return v < val;
}

long long solve(long long L, long long upperB, const vector<Order> &va,
                const vector<Order> &vb) {
  int idxB = vb.size() - 1;
  long long res = 0;
  long long sumL = calcSum(L);
  long long prodL = calcProd(L);
  for (int i = 0; i < va.size(); i++) {
    while (idxB >= 0) {
      if (isSmall(va[i], vb[idxB], upperB, sumL, prodL, L))
        break;
      --idxB;
    }
    res += idxB + 1;
  }
  return res;
}

static Order o[10000000];

int main() {
  string S;
  while (cin >> S) {
    long long L = 0;
    int n = S.size();
    for (int i = 0; i < n; ++i)
      L = 10 * L + S[i] - '0';
    if (n == 1) {
      cout << L << endl;
      continue;
    }
    int upperA = pow10(n / 2);
    int upperB = pow10(n - n / 2);
    vector<Order> vb(upperB);
    for (int i = 0; i < upperB; i++)
      o[i].setVal(i);
    sort(o, o + upperB);
    for (int i = 0; i < upperB; i++)
      vb[i].v = o[i].v;
    if (upperA == upperB) {
      cout << solve(L, upperB, vb, vb) << endl;
    } else {
      vector<Order> va(upperA);
      for (int i = 0; i < upperA; i++)
        va[i].setVal(i);
      sort(va.begin(), va.end());
      cout << solve(L, upperB, va, vb) << endl;
    }
    // vector<Number> vb(upperB);
    // for(int j=0;j<upperB;j++) vb[j].setVal(j);
    // sort(vb.begin(), vb.end());
    // if(upperA == upperB){
    // 	cout << solve(L, upperB, vb, vb) << endl;
    // } else {
    // 	vector<Number> va(upperA);
    // 	for(int j=0;j<upperA;j++) va[j].setVal(j);
    // 	sort(va.begin(), va.end());
    // 	cout << solve(L, upperB, va, vb) << endl;
    // }
  }
}