정수 하나를 크기가 정해진 정수 타입에 차례로 옮겨 담는다.
타입은 i8, u8, i16, u16, i32, u32 여섯 가지다.
i로 시작하면 부호 있는 타입, u로 시작하면 부호 없는 타입이고, 뒤의 수 k는 비트 수다.
k비트 부호 있는 타입에는 -2^(k-1) 이상 2^(k-1) - 1 이하의 정수가 들어간다.
k비트 부호 없는 타입에는 0 이상 2^k - 1 이하의 정수가 들어간다.
옮겨 담는 방법은 두 가지다.
잘라 담기는 타입 이름만 쓴다(i8). 그 타입에 들어가는 정수 가운데 옮겨 담을 값과의 차가 2^k의 배수인 수는 하나뿐이고, 그 수가 결과다.
맞춰 담기는 타입 이름 뒤에 ! 를 붙여 쓴다(i8!). 옮겨 담을 값이 그 타입에 들어가면 그대로, 가장 작은 수보다 작으면 가장 작은 수, 가장 큰 수보다 크면 가장 큰 수가 결과다.
첫 줄에 줄 수 q가 주어진다.
다음 q줄에 정수 v와 단계들이 주어진다. 단계 하나는 옮겨 담는 방법 하나다.
첫 단계는 v를 옮겨 담고, 둘째 단계부터는 바로 앞 단계의 결과를 옮겨 담는다.
줄마다 각 단계의 결과를 차례로 빈칸 하나로 띄워 출력한다.
마지막 줄에는 결과가 옮겨 담기 전의 값과 다른 단계가 모든 줄을 통틀어 몇 개인지 출력한다.
입력
1 ≤ q ≤ 1000. -9000000000000000 ≤ v ≤ 9000000000000000. 한 줄의 단계는 1개 이상 8개 이하다. v와 단계들은 빈칸 하나로 띄워 주어진다
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
정수를 더 작은 타입에 넣을 때 하는 일이 언어마다 달라요. C는 (int8_t)v, C++은 static_cast<std::uint16_t>(v)처럼 크기가 정해진 타입으로 캐스트하면 아래쪽 비트만 남아요. 다만 C 표준은 부호 있는 타입에 들어가지 않는 값을 넣은 결과를 컴파일러가 정하도록 맡겨 두었어요(정의되지 않은 동작은 아니에요). gcc와 clang은 아래쪽 비트만 남기고, C++20부터는 표준이 그렇게 정해요. Java도 (byte)v, (short)v, (int)v가 같은 일을 하지만 부호 없는 타입은 16비트 char뿐이라서 u8은 v & 0xFF, u32는 v & 0xFFFFFFFFL로 잘라요. C#은 sbyte, byte, short, ushort, int, uint가 모두 있고 unchecked 안에서 (sbyte)v처럼 캐스트해요. JS는 수가 한 가지뿐이지만 비트 연산이 값을 먼저 32비트로 자르기 때문에 (v << 24) >> 24(i8), v & 0xff(u8), v | 0(i32), v >>> 0(u32)으로 써요. TS 풀이는 Int8Array 같은 타입 배열의 칸에 넣었다가 꺼내요. Python 정수는 크기에 끝이 없어 저절로 잘리지 않으니 v % size로 직접 계산해요(size가 양수면 Python의 %는 늘 0 이상이에요). 크레이콘도 정수 타입이 따로 없어 %로 계산해요. 맞춰 담기는 어느 풀이든 넓은 타입인 채로 두 끝과 견줘요(C# Math.Clamp, C++ std::clamp). 함정 하나: 크레이콘의 %는 왼쪽 수의 부호를 따라서 -56 % 65536이 -56이에요. 음수이면 2^k를 더해야 해요. 빼먹으면 예시 첫 줄이 -56 -56 -56 -56이 돼요. 함정 둘: 부호 있는 타입에서 딱 2^(k-1)인 값은 범위 밖이에요. i8에 128을 잘라 담으면 -128이에요. 경계를 >로 견주면 예시 넷째 줄이 128 128 127이 돼요. 함정 셋: 단계는 이어져요. 200을 i8에 담은 -56을 u16에 담으면 65480이에요. 단계마다 처음 값을 담으면 예시 첫 줄이 -56 200 200 127이 돼요. 함정 넷: Java에서 v & 0xFFFFFFFF처럼 L을 빼면 마스크가 int -1이고, long으로 넓어져도 -1이라서 아무것도 잘리지 않아요. 예시 둘째 줄이 -1 -1 255 255가 돼요. 함정 다섯: JS에서 v & 0xffffffff의 결과는 부호 있는 32비트 수라서 역시 둘째 줄이 -1 -1 255 255가 돼요. 부호 없는 결과는 >>> 0만 줘요. 함정 여섯: C++에서 std::int8_t, std::uint8_t 값을 그대로 std::cout에 넘기면 수가 아니라 그 코드의 글자가 찍혀요. 예시 첫 줄의 -56 자리에 바이트 하나가 나와요. long long으로 되돌려서 써요. 함정 일곱: C#의 Convert.ToSByte(v)는 자르지 않고 범위를 벗어나면 OverflowException을 던져요. 예시 첫 줄의 200에서 멈춰요.
Pythonmain.py · 34 줄
import sysdef convert(v, step): signed = step[0] == "i" bits = int(step[1:].rstrip("!")) size = 1 << bits # 2^bits lo = -(size // 2) if signed else 0 hi = lo + size - 1 if step.endswith("!"): # 끝값에 맞춰 담기 return max(lo, min(hi, v)) r = v % size # Python의 %는 늘 0 이상 size 미만 if r > hi: # 부호 있는 타입의 위쪽 절반은 음수 r -= size return rlines = sys.stdin.read().split("\n")q = int(lines[0])out = []changed = 0for line in lines[1:q + 1]: parts = line.split() v = int(parts[0]) row = [] for step in parts[1:]: nv = convert(v, step) # 바로 앞 단계의 결과를 다시 옮겨 담는다 if nv != v: changed += 1 v = nv row.append(str(v)) out.append(" ".join(row))out.append(str(changed))print("\n".join(out))
JavaScriptmain.js · 43 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const RANGE = { i8: [-128, 127], u8: [0, 255], i16: [-32768, 32767], u16: [0, 65535], i32: [-2147483648, 2147483647], u32: [0, 4294967295],};// 비트 연산은 먼저 값을 32비트로 자른 뒤에 한다function wrap(v, type) { switch (type) { case "i8": return (v << 24) >> 24; // 아래 8비트를 맨 위로 올렸다가 부호를 채우며 내린다 case "u8": return v & 0xff; case "i16": return (v << 16) >> 16; case "u16": return v & 0xffff; case "i32": return v | 0; default: return v >>> 0; // u32: >>>만 결과를 부호 없는 수로 준다 }}const out = [];let changed = 0;for (let i = 1; i <= q; i++) { const parts = lines[i].trim().split(" "); let v = Number(parts[0]); const row = []; for (const step of parts.slice(1)) { let nv; if (step.endsWith("!")) { const [lo, hi] = RANGE[step.slice(0, -1)]; nv = Math.max(lo, Math.min(hi, v)); } else { nv = wrap(v, step); } if (nv !== v) changed++; v = nv; row.push(v); } out.push(row.join(" "));}out.push(changed);console.log(out.join("\n"));
TypeScriptmain.ts · 47 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);type IntType = "i8" | "u8" | "i16" | "u16" | "i32" | "u32";const RANGE: Record<IntType, [number, number]> = { i8: [-128, 127], u8: [0, 255], i16: [-32768, 32767], u16: [0, 65535], i32: [-2147483648, 2147483647], u32: [0, 4294967295],};// 타입 배열의 칸에 넣으면 그 칸의 크기에 맞게 잘려 들어간다const CELL: Record<IntType, Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array> = { i8: new Int8Array(1), u8: new Uint8Array(1), i16: new Int16Array(1), u16: new Uint16Array(1), i32: new Int32Array(1), u32: new Uint32Array(1),};function wrap(v: number, type: IntType): number { const cell = CELL[type]; cell[0] = v; return cell[0];}const out: string[] = [];let changed = 0;for (let i = 1; i <= q; i++) { const parts: string[] = lines[i].trim().split(" "); let v = Number(parts[0]); const row: number[] = []; for (const step of parts.slice(1)) { let nv: number; if (step.endsWith("!")) { const [lo, hi] = RANGE[step.slice(0, -1) as IntType]; nv = Math.max(lo, Math.min(hi, v)); } else { nv = wrap(v, step as IntType); } if (nv !== v) changed++; v = nv; row.push(v); } out.push(row.join(" "));}out.push(String(changed));console.log(out.join("\n"));
JavaMain.java · 44 줄
import java.io.*;public class Main { // 잘라 담기: Java의 정수 캐스트는 아래쪽 비트만 남긴다 static long wrap(long v, String type) { switch (type) { case "i8": return (byte) v; case "u8": return v & 0xFF; // Java에는 부호 없는 byte가 없다 case "i16": return (short) v; case "u16": return (char) v; // char는 부호 없는 16비트 case "i32": return (int) v; default: return v & 0xFFFFFFFFL; // u32: L을 빼면 0xFFFFFFFF는 int -1이다 } } static long clamp(long v, String type) { int bits = Integer.parseInt(type.substring(1)); long lo = type.charAt(0) == 'i' ? -(1L << (bits - 1)) : 0; long hi = lo + (1L << bits) - 1; return Math.max(lo, Math.min(hi, v)); } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int q = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); int changed = 0; for (int i = 0; i < q; i++) { String[] parts = in.readLine().trim().split(" "); long v = Long.parseLong(parts[0]); for (int j = 1; j < parts.length; j++) { String step = parts[j]; long nv = step.endsWith("!") ? clamp(v, step.substring(0, step.length() - 1)) : wrap(v, step); if (nv != v) changed++; v = nv; if (j > 1) out.append(' '); out.append(v); } out.append('\n'); } out.append(changed).append('\n'); System.out.print(out); }}
C#Main.cs · 59 줄
using System;using System.Text;class Program{ // 잘라 담기: unchecked 캐스트는 아래쪽 비트만 남긴다 static long Wrap(long v, string type) { unchecked { switch (type) { case "i8": return (sbyte)v; case "u8": return (byte)v; case "i16": return (short)v; case "u16": return (ushort)v; case "i32": return (int)v; default: return (uint)v; } } } static long Clamp(long v, string type) { switch (type) { case "i8": return Math.Clamp(v, sbyte.MinValue, sbyte.MaxValue); case "u8": return Math.Clamp(v, byte.MinValue, byte.MaxValue); case "i16": return Math.Clamp(v, short.MinValue, short.MaxValue); case "u16": return Math.Clamp(v, ushort.MinValue, ushort.MaxValue); case "i32": return Math.Clamp(v, int.MinValue, int.MaxValue); default: return Math.Clamp(v, uint.MinValue, uint.MaxValue); } } static void Main() { int q = int.Parse(Console.ReadLine()); var output = new StringBuilder(); int changed = 0; for (int i = 0; i < q; i++) { string[] parts = Console.ReadLine().Trim().Split(' '); long v = long.Parse(parts[0]); for (int j = 1; j < parts.Length; j++) { string step = parts[j]; long nv = step.EndsWith("!") ? Clamp(v, step.TrimEnd('!')) : Wrap(v, step); if (nv != v) changed++; v = nv; if (j > 1) output.Append(' '); output.Append(v); } output.Append('\n'); } output.Append(changed).Append('\n'); Console.Write(output); }}
C++main.cpp · 53 줄
#include <algorithm>#include <cstdint>#include <iostream>#include <sstream>#include <string>// 잘라 담기: static_cast로 크기가 정해진 타입에 넣으면 아래쪽 비트만 남는다long long wrap(long long v, const std::string& type) { if (type == "i8") return static_cast<std::int8_t>(v); if (type == "u8") return static_cast<std::uint8_t>(v); if (type == "i16") return static_cast<std::int16_t>(v); if (type == "u16") return static_cast<std::uint16_t>(v); if (type == "i32") return static_cast<std::int32_t>(v); return static_cast<std::uint32_t>(v);}long long clampTo(long long v, const std::string& type) { int bits = std::stoi(type.substr(1)); long long lo = type[0] == 'i' ? -(1LL << (bits - 1)) : 0; long long hi = lo + (1LL << bits) - 1; return std::clamp(v, lo, hi);}int main() { std::string line; std::getline(std::cin, line); int q = std::stoi(line); int changed = 0; for (int i = 0; i < q; i++) { std::getline(std::cin, line); std::istringstream in(line); long long v; in >> v; std::string step; bool first = true; while (in >> step) { long long nv; if (step.back() == '!') { step.pop_back(); nv = clampTo(v, step); } else { nv = wrap(v, step); } if (nv != v) changed++; v = nv; if (!first) std::cout << ' '; std::cout << v; // long long으로 쓴다. int8_t를 그대로 쓰면 글자로 찍힌다 first = false; } std::cout << '\n'; } std::cout << changed << '\n';}
Cmain.c · 51 줄
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>/* 잘라 담기: 크기가 정해진 타입으로 캐스트하면 아래쪽 비트만 남는다 */static long long wrap(long long v, const char *type) { if (strcmp(type, "i8") == 0) return (int8_t)v; if (strcmp(type, "u8") == 0) return (uint8_t)v; if (strcmp(type, "i16") == 0) return (int16_t)v; if (strcmp(type, "u16") == 0) return (uint16_t)v; if (strcmp(type, "i32") == 0) return (int32_t)v; return (uint32_t)v;}static long long clamp(long long v, const char *type) { int bits = atoi(type + 1); long long lo = type[0] == 'i' ? -(1LL << (bits - 1)) : 0; long long hi = lo + (1LL << bits) - 1; return v < lo ? lo : v > hi ? hi : v;}int main(void) { static char line[256]; int q, changed = 0; if (!fgets(line, sizeof line, stdin)) return 0; q = atoi(line); for (int i = 0; i < q; i++) { if (!fgets(line, sizeof line, stdin)) break; char *tok = strtok(line, " \n"); long long v = atoll(tok); int first = 1; while ((tok = strtok(NULL, " \n")) != NULL) { size_t len = strlen(tok); long long nv; if (tok[len - 1] == '!') { tok[len - 1] = '\0'; nv = clamp(v, tok); } else { nv = wrap(v, tok); } if (nv != v) changed++; v = nv; printf(first ? "%lld" : " %lld", v); first = 0; } putchar('\n'); } printf("%d\n", changed); return 0;}
Craykonmain.cray · 62 줄
// 2를 bits번 곱한 수둘의제곱(bits){ 결과 = 1; 반복 (k = 0; k < bits; k++) { 결과 = 결과 * 2; } 돌려주기 결과;}옮겨담기(v, 단계){ 맞추기 = 단계.끝나나("!"); 이름 = 단계; 만약 (맞추기) { 이름 = 단계.부분문자열(0, 단계.길이 - 1); } 크기 = 둘의제곱(이름.부분문자열(1).수로변환()); lo = 0; 만약 (이름[0] == "i") { lo = 0 - 크기 / 2; } hi = lo + 크기 - 1; 만약 (맞추기) { 돌려주기 수학.큰수(lo, 수학.작은수(hi, v)); } r = v % 크기; // %는 왼쪽 수의 부호를 따라서 음수가 나올 수 있다 만약 (r < 0) { r += 크기; } 만약 (r > hi) { r -= 크기; } 돌려주기 r;}q = 콘솔.줄읽기().수로변환();바뀐수 = 0;반복 (i = 0; i < q; i++){ parts = 콘솔.줄읽기().공백제거().나누기(" "); v = parts[0].수로변환(); 줄 = []; 반복 (j = 1; j < parts.개수; j++) { nv = 옮겨담기(v, parts[j]); 만약 (nv != v) { 바뀐수 += 1; } v = nv; 줄.넣기(v); } 콘솔.쓰기(줄);}콘솔.쓰기(바뀐수);