정수 n개가 든 목록과, 처음에는 비어 있는 클립보드가 있다.
명령 q개를 주어진 차례대로 처리한다.
copy l r은 지금 목록의 l번째부터 r번째까지(둘 다 포함)를 클립보드에 복사한다. 목록은 그대로다.
cut l r은 지금 목록의 l번째부터 r번째까지(둘 다 포함)를 클립보드에 옮기고 목록에서 뺀다.
copy와 cut은 클립보드에 전에 있던 것을 지우고 새 조각으로 바꾼다.
paste p는 클립보드에 든 것을 차례 그대로 지금 목록의 p번째 수 바로 뒤에 끼워 넣는다. p가 0이면 맨 앞에 넣는다.
붙여 넣어도 클립보드는 그대로 남는다. 빈 클립보드를 붙이면 아무 일도 없다.
붙인 뒤 목록의 개수가 M을 넘게 되는 paste는 무시한다(정확히 M개가 되는 것은 붙인다).
번호는 맨 앞 수를 1로 하여 센다.
첫 줄에 n과 M, 둘째 줄에 정수 n개, 셋째 줄에 q, 다음 q줄에 명령이 하나씩 주어진다. 한 줄 안의 값은 빈칸 하나로 띄운다.
명령을 모두 마친 뒤 첫 줄에 목록의 개수를, 둘째 줄에 목록의 수를 차례대로 빈칸 하나로 띄워 출력하라.
목록이 비었으면 둘째 줄에 -를 출력한다.
입력
1 ≤ n ≤ 1,000, n ≤ M ≤ 5,000, 1 ≤ q ≤ 500(쉼표 없이 숫자만 주어진다). 목록의 수는 -999 이상 999 이하. copy와 cut은 그때 목록의 개수를 len이라 할 때 1 ≤ l ≤ r ≤ len(목록이 비었을 때는 주어지지 않는다). paste는 0 ≤ p ≤ len
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
조각을 가리키는 방법이 '시작과 끝'인 언어와 '시작과 개수'인 언어로 갈려요. 시작과 끝(끝은 들어가지 않음): Python a[l-1:r], JS·TS a.slice(l - 1, r), Java a.subList(l - 1, r), C++ 반복자 두 개 a.begin() + (l - 1), a.begin() + r. 시작과 개수: C# a.GetRange(l - 1, r - l + 1), 크레이콘 a.부분목록(l - 1, r - l + 1), C memcpy(clip, a + l - 1, 개수 * sizeof(int)). 같은 JS 안에서도 slice(시작, 끝)과 splice(시작, 개수)가 달라요. 빼기: Python del a[l-1:r], JS·TS a.splice(l - 1, 개수)(뺀 것을 돌려줘서 cut이 한 줄), Java a.subList(l - 1, r).clear(), C# RemoveRange(시작, 개수), C++ a.erase(처음, 끝), C memmove. 끼워 넣기: Python a[p:p] = clip, JS·TS a.splice(p, 0, ...clip), Java a.addAll(p, clip), C# a.InsertRange(p, clip), C++ a.insert(자리, 처음, 끝), C는 memmove로 뒤를 밀고 memcpy. 크레이콘에는 여러 개를 한 번에 빼거나 끼우는 기능이 없어서 앞 조각 부분목록(0, p)에 클립보드와 뒤 조각을 넣기로 이어 새 목록을 만들어요. 함정 ① 끝과 개수를 바꿔 쓰는 실수: slice(l - 1, r - l + 1)이나 GetRange(l - 1, r). JS와 Python은 범위를 벗어나도 오류 없이 줄여서 주고, C#·Java·크레이콘은 오류로 멈춰요. ② 사본인가 창인가: Python 슬라이스, JS slice, C# GetRange, 크레이콘 부분목록은 새 목록을 주지만 Java subList는 원래 목록을 들여다보는 창이에요. 창을 그대로 클립보드로 두면 목록에 끼우거나 뺀 뒤 그 창을 다시 쓸 때 ConcurrentModificationException이 나요. new ArrayList<>(a.subList(l - 1, r))로 사본을 만들어요. ③ 'p번째 뒤'는 0부터 세는 p번 자리예요. p - 1로 쓰면 p = 0일 때 Python은 a[-1:-1]이 되어 맨 끝 수 앞에 끼워져요. ④ 한도는 붙인 뒤의 개수 지금 개수 + 클립보드 개수로 견주고, 정확히 M은 붙여요(<=). ⑤ cut도 클립보드를 새 조각으로 바꿔요. ⑥ r번째도 조각에 들어가요.
Pythonmain.py · 24 줄
import syslines = sys.stdin.read().split("\n")n, limit = map(int, lines[0].split())a = list(map(int, lines[1].split()))q = int(lines[2])clip = [] # 오려 두기 판for line in lines[3:3 + q]: p = line.split() if p[0] == "copy": l, r = int(p[1]), int(p[2]) clip = a[l - 1:r] # 조각은 새 목록(사본)이다 elif p[0] == "cut": l, r = int(p[1]), int(p[2]) clip = a[l - 1:r] del a[l - 1:r] else: at = int(p[1]) if len(a) + len(clip) <= limit: a[at:at] = clip # 빈 조각 자리에 넣으면 끼워 넣기가 된다print(len(a))print(" ".join(map(str, a)) if a else "-")
JavaScriptmain.js · 22 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const limit = Number(lines[0].trim().split(" ")[1]);const a = lines[1].trim().split(" ").map(Number);const q = Number(lines[2]);let clip = []; // 오려 두기 판for (const line of lines.slice(3, 3 + q)) { const p = line.trim().split(" "); if (p[0] === "copy") { const l = Number(p[1]), r = Number(p[2]); clip = a.slice(l - 1, r); // slice(시작, 끝): 끝은 들어가지 않는다. 사본을 준다 } else if (p[0] === "cut") { const l = Number(p[1]), r = Number(p[2]); clip = a.splice(l - 1, r - l + 1); // splice(시작, 개수): 뺀 것들을 돌려준다 } else { const at = Number(p[1]); if (a.length + clip.length <= limit) a.splice(at, 0, ...clip); }}console.log(a.length);console.log(a.length > 0 ? a.join(" ") : "-");
TypeScriptmain.ts · 24 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const limit = Number(lines[0].trim().split(" ")[1]);const a: number[] = lines[1].trim().split(" ").map(Number);const q = Number(lines[2]);let clip: number[] = []; // 오려 두기 판for (const line of lines.slice(3, 3 + q)) { const p = line.trim().split(" "); if (p[0] === "copy") { const l = Number(p[1]), r = Number(p[2]); clip = a.slice(l - 1, r); // slice(시작, 끝): 끝은 들어가지 않는다. 사본을 준다 } else if (p[0] === "cut") { const l = Number(p[1]), r = Number(p[2]); clip = a.splice(l - 1, r - l + 1); // splice(시작, 개수): 뺀 것들을 돌려준다 } else { const at = Number(p[1]); if (a.length + clip.length <= limit) a.splice(at, 0, ...clip); }}console.log(a.length);console.log(a.length > 0 ? a.join(" ") : "-");
JavaMain.java · 43 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import java.util.StringTokenizer;public class Main { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int limit = Integer.parseInt(in.readLine().trim().split(" ")[1]); List<Integer> a = new ArrayList<>(); StringTokenizer st = new StringTokenizer(in.readLine()); while (st.hasMoreTokens()) a.add(Integer.parseInt(st.nextToken())); int q = Integer.parseInt(in.readLine().trim()); List<Integer> clip = new ArrayList<>(); // 오려 두기 판 for (int t = 0; t < q; t++) { String[] p = in.readLine().trim().split(" "); if (p[0].equals("copy")) { int l = Integer.parseInt(p[1]), r = Integer.parseInt(p[2]); // subList는 원래 목록을 들여다보는 창이라서, 새 목록에 담아 사본으로 만든다 clip = new ArrayList<>(a.subList(l - 1, r)); } else if (p[0].equals("cut")) { int l = Integer.parseInt(p[1]), r = Integer.parseInt(p[2]); clip = new ArrayList<>(a.subList(l - 1, r)); a.subList(l - 1, r).clear(); // 창을 비우면 원래 목록에서 빠진다 } else { int at = Integer.parseInt(p[1]); if (a.size() + clip.size() <= limit) a.addAll(at, clip); } } StringBuilder out = new StringBuilder(); out.append(a.size()).append('\n'); if (a.isEmpty()) out.append('-'); for (int i = 0; i < a.size(); i++) { if (i > 0) out.append(' '); out.append(a.get(i)); } System.out.println(out); }}
C#Main.cs · 38 줄
using System;using System.Collections.Generic;using System.Linq;class Program{ static void Main() { int limit = int.Parse(Console.ReadLine().Trim().Split(' ')[1]); List<int> a = Console.ReadLine().Trim().Split(' ').Select(int.Parse).ToList(); int q = int.Parse(Console.ReadLine().Trim()); var clip = new List<int>(); // 오려 두기 판 for (int t = 0; t < q; t++) { string[] p = Console.ReadLine().Trim().Split(' '); if (p[0] == "copy") { int l = int.Parse(p[1]), r = int.Parse(p[2]); clip = a.GetRange(l - 1, r - l + 1); // GetRange(시작, 개수): 사본을 준다 } else if (p[0] == "cut") { int l = int.Parse(p[1]), r = int.Parse(p[2]); clip = a.GetRange(l - 1, r - l + 1); a.RemoveRange(l - 1, r - l + 1); } else { int at = int.Parse(p[1]); if (a.Count + clip.Count <= limit) a.InsertRange(at, clip); } } Console.WriteLine(a.Count); Console.WriteLine(a.Count > 0 ? string.Join(" ", a) : "-"); }}
C++main.cpp · 34 줄
#include <iostream>#include <string>#include <vector>int main() { std::ios::sync_with_stdio(false); std::size_t n, limit; std::cin >> n >> limit; std::vector<int> a(n), clip; // clip: 오려 두기 판 for (int& x : a) std::cin >> x; int q; std::cin >> q; for (int t = 0; t < q; t++) { std::string cmd; std::cin >> cmd; if (cmd == "paste") { int at; std::cin >> at; if (a.size() + clip.size() <= limit) a.insert(a.begin() + at, clip.begin(), clip.end()); } else { int l, r; std::cin >> l >> r; // 반복자 두 개 [시작, 끝)로 조각을 가리킨다. assign은 사본을 만든다 clip.assign(a.begin() + (l - 1), a.begin() + r); if (cmd == "cut") a.erase(a.begin() + (l - 1), a.begin() + r); } } std::cout << a.size() << '\n'; if (a.empty()) std::cout << '-'; for (std::size_t i = 0; i < a.size(); i++) std::cout << (i ? " " : "") << a[i]; std::cout << '\n';}
Cmain.c · 43 줄
#include <stdio.h>#include <string.h>#define MAX 5000static int a[MAX], clip[MAX];int main(void) { int n, limit, q, clipLen = 0; scanf("%d %d", &n, &limit); for (int i = 0; i < n; i++) scanf("%d", &a[i]); scanf("%d", &q); for (int t = 0; t < q; t++) { char cmd[8]; scanf("%7s", cmd); if (strcmp(cmd, "paste") == 0) { int at; scanf("%d", &at); if (n + clipLen <= limit) { /* 뒤쪽을 조각 길이만큼 밀고(겹치므로 memmove) 빈 곳에 조각을 베낀다 */ memmove(a + at + clipLen, a + at, (size_t)(n - at) * sizeof(int)); memcpy(a + at, clip, (size_t)clipLen * sizeof(int)); n += clipLen; } } else { int l, r; scanf("%d %d", &l, &r); clipLen = r - l + 1; memcpy(clip, a + l - 1, (size_t)clipLen * sizeof(int)); /* 조각을 따로 베껴 둔다 */ if (strcmp(cmd, "cut") == 0) { memmove(a + l - 1, a + r, (size_t)(n - r) * sizeof(int)); n -= clipLen; } } } printf("%d\n", n); if (n == 0) printf("-"); for (int i = 0; i < n; i++) printf(i ? " %d" : "%d", a[i]); printf("\n"); return 0;}
Craykonmain.cray · 54 줄
첫줄 = 콘솔.수들읽기();limit = 첫줄[1];a = 콘솔.수들읽기();q = 콘솔.줄읽기().수로변환();clip = [];// 목록 뒤에 다른 목록의 것들을 차례로 붙인다붙이기(목록, 더할것){ 각각 (x 에서 더할것) { 목록.넣기(x); }}반복 (t = 0; t < q; t++){ p = 콘솔.줄읽기().공백제거().나누기(" "); 만약 (p[0] == "paste") { at = p[1].수로변환(); 만약 (a.개수 + clip.개수 <= limit) { // 앞 조각 + 오려 둔 것 + 뒤 조각 뒤 = a.부분목록(at, a.개수 - at); a = a.부분목록(0, at); 붙이기(a, clip); 붙이기(a, 뒤); } } 아니면 { l = p[1].수로변환(); r = p[2].수로변환(); // 부분목록(시작, 개수)는 새 목록(사본)을 준다 clip = a.부분목록(l - 1, r - l + 1); 만약 (p[0] == "cut") { 뒤 = a.부분목록(r, a.개수 - r); a = a.부분목록(0, l - 1); 붙이기(a, 뒤); } }}콘솔.쓰기(a.개수);만약 (a.개수 > 0){ 콘솔.쓰기(a.잇기(" "));}아니면{ 콘솔.쓰기("-");}