글자 n개가 한 줄로 적힌 띠 s가 있다.
명령 q개를 주어진 차례대로 처리한다.
L k는 띠의 맨 앞 글자를 떼어 맨 뒤에 붙이는 일을 k번 한다.
R k는 띠의 맨 뒤 글자를 떼어 맨 앞에 붙이는 일을 k번 한다.
F는 띠 전체를 거꾸로 뒤집는다(맨 뒤 글자가 맨 앞에 온다).
W p c는 지금 띠의 앞에서 p번째 글자를 글자 c로 바꿔 쓴다.
Q p는 지금 띠의 앞에서 p번째 글자를 한 줄에 출력한다.
번호 p는 맨 앞 글자를 1로 하여 센다. k는 n보다 클 수 있다.
첫 줄에 s, 둘째 줄에 q, 다음 q줄에 명령이 하나씩 주어진다. 명령 안의 글자와 수는 빈칸 하나로 띄운다.
Q 명령마다 글자 하나를 한 줄에 출력하고, 마지막 줄에는 명령을 모두 마친 뒤의 띠 전체를 출력하라.
입력
s는 영어 소문자와 숫자로 된 문자열이고 길이 n은 1 ≤ n ≤ 10,000. 1 ≤ q ≤ 10,000. L과 R의 k는 1 ≤ k ≤ 1,000,000,000(쉼표 없이 숫자만 주어진다). W와 Q의 p는 1 ≤ p ≤ n. W의 c는 영어 소문자나 숫자 한 글자. Q 명령은 없을 수도 있다
출력
Q 명령마다 글자 하나씩 한 줄, 마지막 줄에 길이 n인 띠
예시 1 · stdin
abcdef
10
Q 1
L 2
Q 1
F
Q 1
L 1
Q 1
W 2 x
R 9
Q 6
stdout
a
c
b
a
e
dcbaxe
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
글자 번호로 읽는 법은 Python·JS·TS·C#·C·C++·크레이콘이 s[i], Java가 s.charAt(i)예요. 그 자리에 쓰는 것은 언어마다 달라요. Python s[i] = c는 TypeError이고, Java에는 그런 문법이 없고, C#과 TS는 컴파일 오류(읽기 전용)이고, 크레이콘은 '문자열은 한 글자씩 바꿀 수 없어요'로 멈춰요. JS가 가장 위험해요: s[i] = c가 오류 없이 무시돼서(엄격 모드에서만 TypeError) 띠가 그대로예요. 그래서 고칠 수 있는 글자 목록으로 바꿔요: Python list(s), JS·TS [...s], Java toCharArray(), C# ToCharArray(), 크레이콘은 글자를 하나씩 목록에 넣기. C의 char 배열과 C++ std::string은 s[i] = c가 그대로 돼요. 띠를 명령마다 실제로 돌리거나 뒤집지 않고 '지금 띠의 i번 글자는 원래 문자열의 (시작 + 방향 × i)번'이라는 두 수만 고치면 명령 하나가 계산 한 번으로 끝나요. 함정 ① 그 번호는 음수가 될 수 있어요. Python의 %는 늘 0 ~ n − 1을 주지만 C·C++·Java·C#·JS·TS·크레이콘에서는 -2 % 5가 -2예요. JS·TS는 tape[-2]가 오류 없이 undefined라서 그 글자가 빠지거나(join) "undefined"가 찍히고(+로 이을 때), Java·C#·크레이콘은 오류로 멈추고, C·C++은 배열 밖을 읽어요. ((x % n) + n) % n이나 Java Math.floorMod(x, n)을 써요. ② 뒤집은 뒤에는 '맨 앞 글자를 뒤로 보내기'가 원래 문자열에서는 반대쪽으로 가는 일이라, L과 R의 k에 방향을 곱해야 해요. ③ 뒤집을 때 방향만 바꾸면 안 되고, 시작 자리도 지금의 맨 끝 글자로 옮겨야 해요. ④ 사람이 센 p번째는 0부터 세면 p - 1번이에요. ⑤ k는 10억까지라 한 칸씩 k번 돌릴 수 없고, 줄이지 않은 채 int에 쌓으면 세 번 만에 21억을 넘어 값이 돌아요. 먼저 k % n으로 줄여요.
Pythonmain.py · 31 줄
import syslines = sys.stdin.read().split("\n")tape = list(lines[0].strip()) # 문자열은 한 글자씩 고칠 수 없어서 글자 목록으로 바꾼다n = len(tape)q = int(lines[1])# 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)는 tape[(start + step * i) % n]start, step = 0, 1def where(i): return (start + step * i) % n # Python의 %는 음수에서도 0 ~ n-1을 준다out = []for line in lines[2:2 + q]: p = line.split() if p[0] == "L": start = where(int(p[1]) % n) elif p[0] == "R": start = where(-(int(p[1]) % n)) elif p[0] == "F": start = where(n - 1) # 맨 끝 글자가 새 맨 앞 step = -step elif p[0] == "W": tape[where(int(p[1]) - 1)] = p[2] else: out.append(tape[where(int(p[1]) - 1)])out.append("".join(tape[where(i)] for i in range(n)))print("\n".join(out))
JavaScriptmain.js · 28 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const tape = [...lines[0].trim()]; // 문자열은 한 글자씩 고칠 수 없어서 글자 배열로 바꾼다const n = tape.length;const q = Number(lines[1]);// 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)는 tape[(start + step * i) % n]let start = 0, step = 1;// JS의 %는 음수에서 음수를 주므로 n을 더해 한 번 더 나눈다const where = (i) => (((start + step * i) % n) + n) % n;const out = [];for (const line of lines.slice(2, 2 + q)) { const p = line.trim().split(" "); if (p[0] === "L") { start = where(Number(p[1]) % n); } else if (p[0] === "R") { start = where(-(Number(p[1]) % n)); } else if (p[0] === "F") { start = where(n - 1); // 맨 끝 글자가 새 맨 앞 step = -step; } else if (p[0] === "W") { tape[where(Number(p[1]) - 1)] = p[2]; } else { out.push(tape[where(Number(p[1]) - 1)]); }}out.push(tape.map((_, i) => tape[where(i)]).join(""));console.log(out.join("\n"));
TypeScriptmain.ts · 30 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const tape: string[] = [...lines[0].trim()]; // 문자열은 한 글자씩 고칠 수 없어서 글자 배열로 바꾼다const n = tape.length;const q = Number(lines[1]);// 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)는 tape[(start + step * i) % n]let start = 0, step = 1;// TS의 %는 음수에서 음수를 주므로 n을 더해 한 번 더 나눈다const where = (i: number): number => (((start + step * i) % n) + n) % n;const out: string[] = [];for (const line of lines.slice(2, 2 + q)) { const p = line.trim().split(" "); if (p[0] === "L") { start = where(Number(p[1]) % n); } else if (p[0] === "R") { start = where(-(Number(p[1]) % n)); } else if (p[0] === "F") { start = where(n - 1); // 맨 끝 글자가 새 맨 앞 step = -step; } else if (p[0] === "W") { tape[where(Number(p[1]) - 1)] = p[2]; } else { out.push(tape[where(Number(p[1]) - 1)]); }}out.push(tape.map((_, i) => tape[where(i)]).join(""));console.log(out.join("\n"));
JavaMain.java · 35 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { static int n, start = 0, step = 1; // 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)가 있는 원래 자리 static int where(int i) { return Math.floorMod(start + step * i, n); // %와 달리 음수에서도 0 ~ n-1을 준다 } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); char[] tape = in.readLine().trim().toCharArray(); // String은 고칠 수 없어서 char[]로 바꾼다 n = tape.length; int q = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int t = 0; t < q; t++) { String[] p = in.readLine().trim().split(" "); switch (p[0]) { case "L" -> start = where(Integer.parseInt(p[1]) % n); case "R" -> start = where(-(Integer.parseInt(p[1]) % n)); case "F" -> { start = where(n - 1); // 맨 끝 글자가 새 맨 앞 step = -step; } case "W" -> tape[where(Integer.parseInt(p[1]) - 1)] = p[2].charAt(0); default -> out.append(tape[where(Integer.parseInt(p[1]) - 1)]).append('\n'); } } for (int i = 0; i < n; i++) out.append(tape[where(i)]); System.out.println(out); }}
C#Main.cs · 46 줄
using System;using System.Text;class Program{ static int n, start = 0, step = 1; // 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)가 있는 원래 자리 static int Where(int i) { return ((start + step * i) % n + n) % n; // C#의 %는 음수에서 음수를 준다 } static void Main() { char[] tape = Console.ReadLine().Trim().ToCharArray(); // string은 고칠 수 없어서 char[]로 바꾼다 n = tape.Length; int q = int.Parse(Console.ReadLine().Trim()); var output = new StringBuilder(); for (int t = 0; t < q; t++) { string[] p = Console.ReadLine().Trim().Split(' '); switch (p[0]) { case "L": start = Where(int.Parse(p[1]) % n); break; case "R": start = Where(-(int.Parse(p[1]) % n)); break; case "F": start = Where(n - 1); // 맨 끝 글자가 새 맨 앞 step = -step; break; case "W": tape[Where(int.Parse(p[1]) - 1)] = p[2][0]; break; default: output.Append(tape[Where(int.Parse(p[1]) - 1)]).Append('\n'); break; } } for (int i = 0; i < n; i++) output.Append(tape[Where(i)]); Console.WriteLine(output); }}
C++main.cpp · 41 줄
#include <iostream>#include <string>int main() { std::ios::sync_with_stdio(false); std::string tape; // std::string은 tape[i] = c로 한 글자씩 고칠 수 있다 int q; std::cin >> tape >> q; const int n = static_cast<int>(tape.size()); // 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)는 tape[(start + step * i) % n] int start = 0, step = 1; // C++의 %는 음수에서 음수를 주므로 n을 더해 한 번 더 나눈다 auto where = [&](int i) { return ((start + step * i) % n + n) % n; }; std::string out; for (int t = 0; t < q; t++) { char cmd, c; int v; std::cin >> cmd; if (cmd == 'L') { std::cin >> v; start = where(v % n); } else if (cmd == 'R') { std::cin >> v; start = where(-(v % n)); } else if (cmd == 'F') { start = where(n - 1); // 맨 끝 글자가 새 맨 앞 step = -step; } else if (cmd == 'W') { std::cin >> v >> c; tape[where(v - 1)] = c; } else { std::cin >> v; out += tape[where(v - 1)]; out += '\n'; } } for (int i = 0; i < n; i++) out += tape[where(i)]; std::cout << out << '\n';}
Cmain.c · 45 줄
#include <stdio.h>#include <string.h>static char tape[10001]; /* char 배열은 한 글자씩 고칠 수 있다 */static int n, start = 0, step = 1;/* 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)가 있는 원래 자리 */static int where(int i) { return ((start + step * i) % n + n) % n; /* C의 %는 음수에서 음수를 준다 */}int main(void) { int q; scanf("%10000s %d", tape, &q); n = (int)strlen(tape); for (int t = 0; t < q; t++) { char cmd, c; int v; scanf(" %c", &cmd); switch (cmd) { case 'L': scanf("%d", &v); start = where(v % n); break; case 'R': scanf("%d", &v); start = where(-(v % n)); break; case 'F': start = where(n - 1); /* 맨 끝 글자가 새 맨 앞 */ step = -step; break; case 'W': scanf("%d %c", &v, &c); tape[where(v - 1)] = c; break; default: scanf("%d", &v); printf("%c\n", tape[where(v - 1)]); } } for (int i = 0; i < n; i++) putchar(tape[where(i)]); putchar('\n'); return 0;}
Craykonmain.cray · 50 줄
줄 = 콘솔.줄읽기().공백제거();// 문자열은 한 글자씩 고칠 수 없어서 글자 목록으로 바꾼다tape = [];각각 (c 에서 줄){ tape.넣기(c);}n = tape.개수;q = 콘솔.줄읽기().수로변환();// 띠를 실제로 돌리지 않는다. 지금 띠의 i번 글자(0부터)는 tape[(start + step * i) % n]start = 0;step = 1;// 크레이콘의 %는 음수에서 음수를 주므로 n을 더해 한 번 더 나눈다자리(i){ 돌려주기 ((start + step * i) % n + n) % n;}반복 (t = 0; t < q; t++){ p = 콘솔.줄읽기().공백제거().나누기(" "); 선택 (p[0]) { 경우 "L": start = 자리(p[1].수로변환() % n); 그만; 경우 "R": start = 자리(-(p[1].수로변환() % n)); 그만; 경우 "F": // 맨 끝 글자가 새 맨 앞 start = 자리(n - 1); step = -step; 그만; 경우 "W": tape[자리(p[1].수로변환() - 1)] = p[2]; 그만; 그밖에: 콘솔.쓰기(tape[자리(p[1].수로변환() - 1)]); 그만; }}끝 = [];반복 (i = 0; i < n; i++){ 끝.넣기(tape[자리(i)]);}콘솔.쓰기(끝.잇기(""));