One integer is moved, step by step, into integer types of fixed size.
There are six types: i8, u8, i16, u16, i32 and u32.
A name starting with i is a signed type, one starting with u is an unsigned type, and the number k after it is the number of bits.
A k-bit signed type holds the integers from -2^(k-1) to 2^(k-1) - 1.
A k-bit unsigned type holds the integers from 0 to 2^k - 1.
There are two ways to move a value.
A wrapping move is written as the type name alone (i8). Among the integers the type holds, exactly one differs from the value being moved by a multiple of 2^k, and that integer is the result.
A clamping move is written as the type name followed by ! (i8!). If the value being moved fits in the type, the result is the value itself; if it is below the smallest number, the result is the smallest number; if it is above the largest number, the result is the largest number.
The first line gives the number of lines q.
Each of the next q lines gives an integer v and some steps. One step is one way of moving.
The first step moves v, and every later step moves the result of the step just before it.
For each line, print the result of each step in order, separated by single spaces.
On the last line, print how many steps, over all lines together, gave a result different from the value before the move.
Input
1 ≤ q ≤ 1000. -9000000000000000 ≤ v ≤ 9000000000000000. A line has from 1 to 8 steps. v and the steps are separated by single spaces
Output
q lines, then a last line with the number of steps that changed the value
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
What happens when an integer goes into a smaller type differs by language. In C a cast to a fixed-size type such as (int8_t)v, and in C++ static_cast<std::uint16_t>(v), keeps only the low bits. Strictly, the C standard leaves the result of putting a value that does not fit into a signed type up to the compiler (implementation-defined, not undefined behaviour); gcc and clang keep the low bits, and since C++20 the standard itself says so. Java's (byte)v, (short)v and (int)v do the same, but its only unsigned type is the 16-bit char, so u8 is cut with v & 0xFF and u32 with v & 0xFFFFFFFFL. C# has all of sbyte, byte, short, ushort, int and uint, and you cast as in (sbyte)v inside unchecked. JS has only one kind of number, but bitwise operators first cut the value to 32 bits, so you write (v << 24) >> 24 (i8), v & 0xff (u8), v | 0 (i32) and v >>> 0 (u32). The TS solution stores the value into a slot of a typed array such as Int8Array and reads it back. Python integers have no size limit and never get cut on their own, so you compute v % size yourself (with a positive size, Python's % is never negative). Craykon has no separate integer types either and computes with %. For the clamping move every solution compares against the two ends while still in the wide type (C# Math.Clamp, C++ std::clamp). Trap one: Craykon's % follows the sign of the left number, so -56 % 65536 is -56. When it is negative you must add 2^k. Without that, the first line of the example becomes -56 -56 -56 -56. Trap two: in a signed type the value exactly 2^(k-1) is out of range. Wrapping 128 into i8 gives -128. Comparing the boundary with > turns the fourth line of the example into 128 128 127. Trap three: the steps form a chain. 200 moved into i8 is -56, and that moved into u16 is 65480. Moving the original value at every step turns the first line of the example into -56 200 200 127. Trap four: in Java, leaving out the L as in v & 0xFFFFFFFF makes the mask the int -1, which is still -1 after widening to long, so nothing is cut. The second line of the example becomes -1 -1 255 255. Trap five: in JS the result of v & 0xffffffff is a signed 32-bit number, so again the second line becomes -1 -1 255 255. Only >>> 0 gives an unsigned result. Trap six: in C++, passing a std::int8_t or std::uint8_t value straight to std::cout prints the character with that code, not a number. One byte appears where -56 should be on the first line of the example. Convert back to long long before printing. Trap seven: C#'s Convert.ToSByte(v) does not cut; it throws OverflowException when the value is out of range. It stops at the 200 on the first line of the example.
Pythonmain.py · 34 lines
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 lines
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 lines
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 lines
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 lines
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 lines
#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 lines
#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 lines
// 2를 bits번 곱한 수둘의제곱(bits){ 결과 = 1; for (k = 0; k < bits; k++) { 결과 = 결과 * 2; } return 결과;}옮겨담기(v, 단계){ 맞추기 = 단계.EndsWith("!"); 이름 = 단계; if (맞추기) { 이름 = 단계.Substring(0, 단계.Length - 1); } 크기 = 둘의제곱(이름.Substring(1).ToNumber()); lo = 0; if (이름[0] == "i") { lo = 0 - 크기 / 2; } hi = lo + 크기 - 1; if (맞추기) { return Mathf.Max(lo, Mathf.Min(hi, v)); } r = v % 크기; // %는 왼쪽 수의 부호를 따라서 음수가 나올 수 있다 if (r < 0) { r += 크기; } if (r > hi) { r -= 크기; } return r;}q = Console.ReadLine().ToNumber();바뀐수 = 0;for (i = 0; i < q; i++){ parts = Console.ReadLine().Trim().Split(" "); v = parts[0].ToNumber(); 줄 = []; for (j = 1; j < parts.Count; j++) { nv = 옮겨담기(v, parts[j]); if (nv != v) { 바뀐수 += 1; } v = nv; 줄.Add(v); } Console.WriteLine(줄);}Console.WriteLine(바뀐수);