#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <map>
#include <algorithm>  // std::unique
#include <cmath>
#include <limits.h>
#include <queue>
#include <unordered_map>
#include <sstream>      // std::ostringstream
#include <bitset>
#include <iomanip>
#include <functional>
#include <set>


#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;

using ll = long long;
constexpr auto PrimeBigNum10_9_7 = 1000000007;

#define OUTPUT_DEBUG_LOG

template <typename T>
void DisplayAnswer(const T& v) {
	cout << v << endl;
}
template <typename T>
void DisplayAnswers(const vector<T>& vs) {
	for (const auto& v : vs) {
		cout << v << endl;
	}
}

template <typename T>
void DisplayAnswerOneLine(const vector<T>& vs) {
	for (const auto& v : vs) {
		cout << v << ' ';
	}
	cout << endl;
}


std::vector<std::string> split(const std::string &str, char sep)
{
	std::vector<std::string> v;
	std::stringstream ss(str);
	std::string buffer;
	while (std::getline(ss, buffer, sep)) {
		v.push_back(buffer);
	}
	return v;
}


// 素数判定
template <typename T>
bool IsPrimeNumber(T value) {

	for (int i = 2; i * i <= value; ++i) {
		if ((value % i) == 0) {
			return true;
		}
	}
	return false;
}

// 桁数判定
template <typename T>
T GetFigureLength(T value) {
	T figure = 1;
	while (value >= 10) {
		value /= 10;
		++figure;
	}
	return figure;
}

// 素因数分解結果
template <typename T>
map<T, T> GetPrimeFactorize(T value) {

	map<T, T> res;

	for (T i = 2; i * i <= value; ++i) {
		if ((value%i) != 0)	continue;

		T count = 0;
		while ((value % i) == 0) {
			value /= i;
			++count;
		}

		res[i] = count;
	}

	if (value != 1) {
		res[value] = 1;
	}
	return res;
}


void DebugPrint(const vector<ll>& vec) {
	cout << "{";
	for (auto itr = vec.begin(); itr != vec.end(); ++itr) {
		cout << *itr << ",";
	}
	cout << "}" << endl;
}

// valueが2のx乗以下である計算
ll calc2x(ll value) {
	ll n = 0;
	while (value > 0) {
		value /= 2;
		++n;
	}
	return n;
}



struct Vec2 {
	double x;
	double y;

	void rotate(double rad) {
		double s = sin(rad);
		double c = cos(rad);
		double tmpX = this->x*c - this->y*s;
		double tmpY = this->x*s + this->y*c;
		this->x = tmpX;
		this->y = tmpY;
	}
};

struct IntPos {
	int x, y;

	bool operator == (const IntPos& v) const {
		if (v.x != x)	return false;
		if (v.y != y)	return false;
		return true;
	}

	IntPos operator +(const IntPos& p) {
		
		return IntPos{ this->x + p.x, this->y + p.y };
	}

	static double CalcDistance(const IntPos& p1, const IntPos&p2) {
		return pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2);
	}
};


class Field {
public:
	Field(int width, int height, int value) {

		for (int i = 0; i < height; ++i) {
			vector<int> list(width, value);
			_field.push_back(list);
		}

		_areaMin = { -1, -1 };
		_areaMax = { width,height };
	}

	bool CanAccess(const IntPos& p) const {
		if (p.x <= _areaMin.x)	return false;
		if (p.y <= _areaMin.y)	return false;
		if (p.x >= _areaMax.x)	return false;
		if (p.y >= _areaMax.y)	return false;
		return true;
	}
	void Set(const IntPos& p, int v) {
		_field[p.x][p.y] = v;
	}
	int Get(const IntPos& p)const {
		return _field[p.x][p.y];
	}

	void SetEnableArea(const vector<IntPos>& poslist, int addArea=0) {
		vector<int> listX, listY;
		for (const auto& p : poslist) {
			listX.push_back(p.x);
			listY.push_back(p.y);
		}

		sort(listX.begin(), listX.end());
		sort(listY.begin(), listY.end());

		_areaMax.x = std::min((int)_field.size(), listX[listX.size() - 1] + 2);
		_areaMax.y = std::min((int)_field.size(), listY[listY.size() - 1] + 2);

		_areaMin.x = std::max(0, listX[0] - 2);
		_areaMin.y = std::max(0, listY[0] - 2);
	}

	void DebugDisplay(int digit, function<bool(int, const IntPos&)> isOutputInstead = nullptr ) {
#ifdef OUTPUT_DEBUG_LOG

		static int displayCounter = 0;
		cout << displayCounter++ << "---------" << endl;
		for (int i = _areaMin.x + 1; i < _areaMax.x; ++i) {
			for (int j = _areaMin.y + 1; j < _areaMax.y; ++j) {
				
				if (!isOutputInstead || !isOutputInstead(digit, IntPos{ i,j })) {
					cout << std::setw(digit) << Get({ i,j });
				}

			}
			cout << endl;
		}
#endif
	}

private:
	vector<vector<int>> _field;

	IntPos _areaMax;
	IntPos _areaMin;
};

class Dijkstra {
public:
	struct Definition {
		IntPos posStart;
		IntPos posGoal;
		int width, height;
		vector<IntPos> moveList;
		vector<IntPos> noEntryList;
		int debugDisplayDigit;
		Definition() :width(0),height(0), debugDisplayDigit(3){}
	};

	Dijkstra(const Definition& definition) 
	: _fieldInitValue(definition.width*definition.height)
	, _debugDisplayDigit(definition.debugDisplayDigit)
	, _posStart(definition.posStart)
	, _posGoal(definition.posGoal)
	, _field(definition.width, definition.height, _fieldInitValue)
	, _moveList(definition.moveList){
		for (const auto& pos : definition.noEntryList) {
			_field.Set(pos, MAP_NO_ENTRY);
		}
		{
			auto posList = definition.noEntryList;
			posList.push_back(_posStart);
			posList.push_back(_posGoal);
			_field.SetEnableArea(posList, 2);
		}
	}

	static const int NO_ANSWER = -1;
	int Calc() {
		vector<QueueParam> queue;
		queue.push_back(QueueParam{ _posStart, 1 });

		while (queue.size() > 0) {

			DebugDisplay();
			auto param = *queue.begin();
			queue.erase(queue.begin());

			vector<QueueParam> tmpQueue;
			for (const auto& move : _moveList) {
				auto newPos = param.pos + move;
				if (_field.CanAccess(newPos)) {
					if (IsSet(_field.Get(newPos), param.count)) {
						_field.Set(newPos, param.count);
						QueueParam p{ newPos, param.count + 1};
						tmpQueue.push_back(p);
					}

				}
			}

			if (_field.Get(_posGoal) < param.count + 1)	continue;

			queue.insert(queue.end(), tmpQueue.begin(), tmpQueue.end());
		}

		auto ans = _field.Get(_posGoal);
		if (ans == _fieldInitValue)	return NO_ANSWER;
		return ans;
	}


	void DebugDisplay() {
#ifdef OUTPUT_DEBUG_LOG

		_field.DebugDisplay(_debugDisplayDigit, [this](int digit, const IntPos& pos) {
			auto v = _field.Get(pos);

			auto getV = [this, v]() {
				string str = to_string(v);
				if (v == MAP_NO_ENTRY) {
					str = "x";
				}
				else if (v == _fieldInitValue) {
					str = "-";
				}
				return str;
			};

			if (_posStart == pos ) {
				string tmp = "S" + getV();
				cout << std::setw(digit) << tmp;
			}
			else if (_posGoal == pos ) {
				string tmp = "G" + getV();
				cout << std::setw(digit) << tmp;
			}
			else if (v == MAP_NO_ENTRY) {
				cout << std::setw(digit) << getV();
			}
			else if (v == _fieldInitValue) {
				cout << std::setw(digit) << getV();
			}
			else {
				return false;
			}
			return true;
		});
#endif
	}

private:
	static const int MAP_NO_ENTRY = -1;
	struct QueueParam {
		IntPos pos;
		int count;
	};
private:
	bool IsSet(int value, int count) const {
		if (value == MAP_NO_ENTRY)	return false;
		if (value > count) return true;
		return false;
	}
private:
	const int _fieldInitValue;
	const int _debugDisplayDigit;

	IntPos _posStart;
	IntPos _posGoal;
	Field _field;
	vector<IntPos> _moveList;

};
//  2: b
// 26: z
// 27:aa
// 51:ay
// 52:az xxx
// 53:ba

// 18281:aaac
// 475253:
// 123456789:jjddja
int main(void) {

	ll N;
	cin >> N;
	string name;

	while (N > 0) {
		N--;
		name += 'a' + ((N) % 26);
		if (N < 26)	break;
		N /= 26;
	};
	reverse(name.begin(), name.end());

	DisplayAnswer(name);


	return 0;
}


Measured memory_bytes: 3632