#include <bits/stdc++.h>
using namespace std;
using LL = long long;
template <typename T>
inline T& unused_var(T& v) {
  return v;
}
struct cww {
  cww() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed;
    cout << setprecision(10);
  }
};
cww star;
template <typename T>
std::istream& operator>>(std::istream& is, std::vector<T>& v) {
  for (auto& it : v) is >> it;
  return is;
}
class reverse_range {
 private:
  struct I {
    int x;
    int operator*() { return x - 1; }
    bool operator!=(I& lhs) { return x > lhs.x; }
    void operator++() { --x; }
  };
  I i, n;

 public:
  reverse_range(int n) : i({0}), n({n}) {}
  reverse_range(int i, int n) : i({i}), n({n}) {}
  I& begin() { return n; }
  I& end() { return i; }
};
class range {
 private:
  struct I {
    int x;
    int operator*() { return x; }
    bool operator!=(I& lhs) { return x < lhs.x; }
    void operator++() { ++x; }
  };
  I i, n;

 public:
  range(int n) : i({0}), n({n}) {}
  range(int i, int n) : i({i}), n({n}) {}
  I& begin() { return i; }
  I& end() { return n; }
  reverse_range operator!() { return reverse_range(*i, *n); }
};
template <typename T>
struct min_op {
  static T exec(const T l, const T r) { return l < r ? l : r; }
};
template <typename T>
struct max_op {
  static T exec(const T l, const T r) { return l > r ? l : r; }
};
template <typename F, typename T>
inline T multi_op(T&& v) {
  return v;
}
template <typename F, typename T, typename... Ts>
inline T multi_op(const T head, Ts&&... tail) {
  return F::exec(head, multi_op<F>(tail...));
}
template <typename T, typename... Ts>
inline T multi_min(T&& head, Ts&&... tail) {
  return multi_op<min_op<T> >(head, tail...);
}
template <typename T, typename... Ts>
inline T multi_max(T&& head, Ts&&... tail) {
  return multi_op<max_op<T> >(head, tail...);
}
template <typename F, typename T, typename... Ts>
inline bool ch_op(T& target, Ts&&... candidates) {
  const T old = target;
  target = multi_op<F>(target, candidates...);
  return old != target;
}
template <typename T, typename... Ts>
inline bool chmin(T& target, Ts&&... candidates) {
  return ch_op<min_op<T> >(target, candidates...);
}
template <typename T, typename... Ts>
inline bool chmax(T& target, Ts&&... candidates) {
  return ch_op<max_op<T> >(target, candidates...);
}
const pid_t pid = getpid();
class XorShift32 {
 private:
  unsigned value;
  inline void update() {
    value = value ^ (value << 13);
    value = value ^ (value >> 17);
    value = value ^ (value << 5);
  }
  inline unsigned get() {
    unsigned v = value;
    update();
    return v;
  }

 public:
  template <int bit = 31>
  inline int next_int() {
    return (int)(get() >> (32 - bit));
  }
  template <int bit = 31>
  inline int next_signed() {
    unsigned v = get();
    return (int)((v >> (31 - bit)) - (1 << (bit)));
  }
  template <int bit = 31>
  inline int range_max() {
    return (int)((1u << bit) - 1);
  };
  XorShift32(const unsigned seed) {
    value = seed;
    update();
  }
  XorShift32() : XorShift32(pid) {}
};
template <typename T, typename U>
inline std::vector<T> wrapGrid(std::vector<T> grid, U material) {
  std::vector<T> wrappedGrid(grid.size(), T(grid[0].size(), material));
  for (std::size_t i = 0; i < grid.size(); i++) {
    for (std::size_t j = 0; j < grid[i].size(); j++) {
      wrappedGrid[i + 1][j + 1] = grid[i][j];
    }
  }
  return wrappedGrid;
}
constexpr int dr4[] = {0, 1, 0, -1};
constexpr int dc4[] = {-1, 0, 1, 0};
template <typename T>
std::string join(std::vector<T> v, char delimiter) {
  std::stringstream ss;
  bool isFirst = true;
  for (auto& it : v) {
    if (!isFirst) {
      ss << delimiter;
    }
    isFirst = false;
    ss << it;
  }
  return ss.str();
}
int sn(LL n) {
  auto s = to_string(n);
  return accumulate((s).begin(), (s).end(), 0) - s.size() * '0';
}
int main() {
  int k;
  cin >> k;
  vector<LL> v;
  for (int i : range(1, min(10, k + 1))) {
    v.push_back(i);
  }
  string t = "09";
  while ((int)v.size() < k) {
    if (t[0] == '9') {
      t = "1" + t;
    } else {
      t[0]++;
    }
    LL p = stoll(t);
    while (v.size() > 0 && v.back() * sn(p) > p * sn(v.back())) {
      v.pop_back();
    }
    v.push_back(p);
  }
  cout << join(v, '\n') << endl;
  return 0;
}
