#include using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int targetScore; cin >> targetScore; // minEvents[score] = minimum playback events needed for this score. const int INF = 1e9; vector minEvents(targetScore + 1, INF); minEvents[0] = 0; for (int score = 1; score <= targetScore; score++) { for (int length = 1; length * length <= score; length++) { minEvents[score] = min( minEvents[score], length + minEvents[score - length * length] ); } } string trace; int remainingScore = targetScore; char startPath = 'L'; while (remainingScore > 0) { int shortestEndingL = -1; int longestValidLength = -1; for (int length = 1; length * length <= remainingScore; length++) { // Only consider blocks that preserve minimum total length. if (length + minEvents[remainingScore - length * length] != minEvents[remainingScore]) { continue; } // Lengths are visited in increasing order. longestValidLength = length; char endPath; if (length % 2 == 1) { endPath = startPath; } else { endPath = (startPath == 'L') ? 'G' : 'L'; } // Keep the first, hence shortest, valid block ending in L. if (endPath == 'L' && shortestEndingL == -1) { shortestEndingL = length; } } int chosenLength; if (shortestEndingL != -1) { chosenLength = shortestEndingL; } else { chosenLength = longestValidLength; } // Append the chosen alternating block. char currentPath = startPath; for (int i = 0; i < chosenLength; i++) { trace.push_back(currentPath); currentPath = (currentPath == 'L') ? 'G' : 'L'; } remainingScore -= chosenLength * chosenLength; // Repeating the previous ending path creates a block boundary. startPath = trace.back(); } cout << trace << '\n'; }