{ }codelper
상수넘침(오버플로)정수 나눗셈P0387

데이터 요금제의 초과 요금

어느 통신사의 요금제는 한 달에 데이터를 3 GB 500 MB까지 기본으로 준다. 기본으로 주는 양을 넘겨 쓴 데이터는 100 MB짜리 묶음으로 센다. 넘은 양이 묶음 하나를 다 채우지 못해도 묶음 하나로 센다. 묶음 하나마다 550원을 더 낸다. 쓴 양이 기본으로 주는 양과 같거나 그보다 적으면 넘은 묶음은 0개이고 더 낼 요금도 0원이다. 단위는 1 KB = 1,024 B, 1 MB = 1,024 KB, 1 GB = 1,024 MB이다. 한 달 동안의 사용 기록 n개가 주어지면 쓴 데이터의 합, 넘은 묶음 수, 더 낼 요금을 구한다.

입력
첫 줄에 사용 기록의 수 n이 주어진다(1 ≤ n ≤ 300). 다음 n개 줄에 쓴 양을 나타내는 정수 a와 단위 u가 빈칸 하나로 띄워 주어진다(1 ≤ a ≤ 1,023). u는 B, KB, MB, GB 가운데 하나이다.
출력
첫 줄에 쓴 데이터의 합을 B 단위의 정수로 출력한다. 둘째 줄에 넘은 묶음 수를 출력한다. 셋째 줄에 더 낼 요금을 원 단위의 정수로 출력한다. 세 수 모두 쉼표 없이 숫자만 출력한다.
예시 1 · stdin
4
3 GB
900 MB
512 KB
100 B
stdout
4165468260
5
2750
예시 2 · stdin
2
600 MB
3 GB
stdout
3850371072
1
550
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

바뀌지 않는 값에 이름을 붙여 두는 상수를 만드는 방법이 언어마다 달라요. Python에는 상수 문법이 없어서 KB = 1024처럼 대문자 이름으로 적어 두고 바꾸지 않기로 약속해요.
다시 값을 넣어도 오류가 나지 않아요. JavaScript의 const는 다시 값을 넣으면 실행 중에 TypeError가 나고, TypeScript는 컴파일 오류로 미리 막아요. Java는 static final, C#은 const, C++은 constexpr를 쓰고, 셋 다 다시 값을 넣으면 컴파일 오류예요. C는 #define KB 1024LL처럼 매크로로 두는데, 매크로는 값이 아니라 글자를 그대로 바꿔 끼워요. 크레이콘에는 상수가 없어서 바꾸지 않기로 약속한 변수로 둬요. MB = 1024 * KB처럼 상수를 다른 상수로 만들어 두면 1,024라는 수를 한 곳에만 적게 돼요. 함정 하나: 상수 식의 넘침이에요.
3 GB는 3,221,225,472 B라서 32비트 정수(최대 2,147,483,647)에 담기지 않아요.
Java에서 static final long ALLOWANCE = 3 * 1024 * 1024 * 1024 + 500 * 1024 * 1024;라고 쓰면 long에 넣기 전에 int끼리 곱해서 오류 없이 -549,453,824가 돼요.
예시 1에서 묶음 수가 5가 아니라 45로 나와요.
3 * 1024 * 1024 * 1024를 C#의 const와 C++의 constexpr는 컴파일 오류로 막고, C는 경고만 하고 컴파일돼요(결과는 정해져 있지 않아요).
1024L처럼 첫 값을 64비트 정수로 적으면 돼요.
Python, JavaScript, 크레이콘은 이 크기의 정수에서 넘치지 않아요. 함정 둘: 괄호 없는 매크로예요.
C에서 #define ALLOWANCE 3 * GB + 500 * MB라고 쓰면 total - ALLOWANCE가 total - 3 * GB + 500 * MB로 펼쳐져서 500 MB를 빼지 않고 더해요.
예시 1에서 묶음 수가 15로 나와요. 함정 셋: 단위예요.
이 문제의 1 KB는 1,000 B가 아니라 1,024 B예요.
상수 한 줄을 1000으로 적으면 예시 1의 첫 줄이 4165468260이 아니라 3900512100으로 나와요. 함정 넷: 올림이에요.
예시 1은 넘은 양이 419,954,788 B로 묶음 4개를 조금 넘으니 5묶음이에요.
내림하면 4가 나와요. 함정 다섯: 딱 떨어질 때예요.
예시 2는 넘은 양이 정확히 100 MB라서 1묶음이에요.
올림을 몫 + 1로 계산하면 2가 나와요.

Pythonmain.py · 24 줄
import sys # 파이썬에는 상수 문법이 없다: 대문자 이름은 "바꾸지 말자"는 약속일 뿐이다KB = 1024MB = 1024 * KBGB = 1024 * MBALLOWANCE = 3 * GB + 500 * MB  # 기본으로 주는 양BLOCK = 100 * MB               # 넘은 양을 세는 묶음PRICE = 550                    # 묶음 하나의 요금(원)UNIT = {"B": 1, "KB": KB, "MB": MB, "GB": GB} lines = sys.stdin.read().split("\n")n = int(lines[0])total = 0for i in range(1, n + 1):    a, u = lines[i].split()    total += int(a) * UNIT[u] blocks = 0if total > ALLOWANCE:    blocks = (total - ALLOWANCE + BLOCK - 1) // BLOCK  # 올림print(total)print(blocks)print(blocks * PRICE)
JavaScriptmain.js · 24 줄
// const는 다시 넣으면 실행 중에 TypeError가 난다const KB = 1024;const MB = 1024 * KB;const GB = 1024 * MB;const ALLOWANCE = 3 * GB + 500 * MB; // 기본으로 주는 양const BLOCK = 100 * MB; // 넘은 양을 세는 묶음const PRICE = 550; // 묶음 하나의 요금(원)const UNIT = { B: 1, KB: KB, MB: MB, GB: GB }; const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);let total = 0;for (let i = 1; i <= n; i++) {  const [a, u] = lines[i].trim().split(" ");  total += Number(a) * UNIT[u];} let blocks = 0;if (total > ALLOWANCE) {  blocks = Math.floor((total - ALLOWANCE + BLOCK - 1) / BLOCK); // 올림}console.log(String(total));console.log(String(blocks));console.log(String(blocks * PRICE));
TypeScriptmain.ts · 26 줄
import { readFileSync } from "node:fs"; // const는 다시 넣으면 컴파일 오류다const KB: number = 1024;const MB: number = 1024 * KB;const GB: number = 1024 * MB;const ALLOWANCE: number = 3 * GB + 500 * MB; // 기본으로 주는 양const BLOCK: number = 100 * MB; // 넘은 양을 세는 묶음const PRICE: number = 550; // 묶음 하나의 요금(원)const UNIT: Record<string, number> = { B: 1, KB: KB, MB: MB, GB: GB }; const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);let total: number = 0;for (let i = 1; i <= n; i++) {  const [a, u] = lines[i].trim().split(" ");  total += Number(a) * UNIT[u];} let blocks: number = 0;if (total > ALLOWANCE) {  blocks = Math.floor((total - ALLOWANCE + BLOCK - 1) / BLOCK); // 올림}console.log(String(total));console.log(String(blocks));console.log(String(blocks * PRICE));
JavaMain.java · 40 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    // static final 상수. 1024L처럼 L을 붙여야 곱셈이 long으로 계산된다    static final long KB = 1024L;    static final long MB = 1024 * KB;    static final long GB = 1024 * MB;    static final long ALLOWANCE = 3 * GB + 500 * MB; // 기본으로 주는 양    static final long BLOCK = 100 * MB;              // 넘은 양을 세는 묶음    static final long PRICE = 550;                   // 묶음 하나의 요금(원)     static long unit(String u) {        switch (u) {            case "KB": return KB;            case "MB": return MB;            case "GB": return GB;            default: return 1;        }    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        long total = 0;        for (int i = 0; i < n; i++) {            String[] parts = br.readLine().trim().split(" ");            total += Long.parseLong(parts[0]) * unit(parts[1]);        }         long blocks = 0;        if (total > ALLOWANCE) {            blocks = (total - ALLOWANCE + BLOCK - 1) / BLOCK; // 올림        }        System.out.println(total);        System.out.println(blocks);        System.out.println(blocks * PRICE);    }}
C#Main.cs · 43 줄
using System; class Program{    // const 상수: 컴파일할 때 값이 정해진다    const long KB = 1024L;    const long MB = 1024 * KB;    const long GB = 1024 * MB;    const long ALLOWANCE = 3 * GB + 500 * MB; // 기본으로 주는 양    const long BLOCK = 100 * MB;              // 넘은 양을 세는 묶음    const long PRICE = 550;                   // 묶음 하나의 요금(원)     static long Unit(string u)    {        switch (u)        {            case "KB": return KB;            case "MB": return MB;            case "GB": return GB;            default: return 1;        }    }     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        long total = 0;        for (int i = 0; i < n; i++)        {            string[] parts = Console.ReadLine().Trim().Split(' ');            total += long.Parse(parts[0]) * Unit(parts[1]);        }         long blocks = 0;        if (total > ALLOWANCE)        {            blocks = (total - ALLOWANCE + BLOCK - 1) / BLOCK; // 올림        }        Console.WriteLine(total);        Console.WriteLine(blocks);        Console.WriteLine(blocks * PRICE);    }}
C++main.cpp · 34 줄
#include <iostream>#include <string>using namespace std; // constexpr 상수: 컴파일할 때 계산되고, 넘치면 컴파일 오류다constexpr long long KB = 1024;constexpr long long MB = 1024 * KB;constexpr long long GB = 1024 * MB;constexpr long long ALLOWANCE = 3 * GB + 500 * MB; // 기본으로 주는 양constexpr long long BLOCK = 100 * MB;              // 넘은 양을 세는 묶음constexpr long long PRICE = 550;                   // 묶음 하나의 요금(원) int main() {    int n;    cin >> n;    long long total = 0;    for (int i = 0; i < n; i++) {        long long a;        string u;        cin >> a >> u;        long long unit = 1;        if (u == "KB") unit = KB;        else if (u == "MB") unit = MB;        else if (u == "GB") unit = GB;        total += a * unit;    }     long long blocks = 0;    if (total > ALLOWANCE) {        blocks = (total - ALLOWANCE + BLOCK - 1) / BLOCK; // 올림    }    cout << total << '\n' << blocks << '\n' << blocks * PRICE << '\n';    return 0;}
Cmain.c · 33 줄
#include <stdio.h>#include <string.h> /* #define은 글자를 그대로 바꿔 끼운다: 식은 꼭 괄호로 싼다 */#define KB 1024LL#define MB (1024 * KB)#define GB (1024 * MB)#define ALLOWANCE (3 * GB + 500 * MB) /* 기본으로 주는 양 */#define BLOCK (100 * MB)              /* 넘은 양을 세는 묶음 */#define PRICE 550                     /* 묶음 하나의 요금(원) */ int main(void) {    int n;    if (scanf("%d", &n) != 1) return 1;    long long total = 0;    for (int i = 0; i < n; i++) {        long long a;        char u[4];        if (scanf("%lld %3s", &a, u) != 2) return 1;        long long unit = 1;        if (strcmp(u, "KB") == 0) unit = KB;        else if (strcmp(u, "MB") == 0) unit = MB;        else if (strcmp(u, "GB") == 0) unit = GB;        total += a * unit;    }     long long blocks = 0;    if (total > ALLOWANCE) {        blocks = (total - ALLOWANCE + BLOCK - 1) / BLOCK; /* 올림 */    }    printf("%lld\n%lld\n%lld\n", total, blocks, blocks * PRICE);    return 0;}
Craykonmain.cray · 38 줄
// 크레이콘에는 상수가 없다: 바꾸지 않기로 약속한 변수로 둔다킬로 = 1024;메가 = 1024 * 킬로;기가 = 1024 * 메가;기본량 = 3 * 기가 + 500 * 메가; // 기본으로 주는 양묶음 = 100 * 메가; // 넘은 양을 세는 묶음묶음요금 = 550; // 묶음 하나의 요금(원) 기록수 = 콘솔.줄읽기().수로변환();합 = 0;반복 (i = 0; i < 기록수; i++){    칸들 = 콘솔.줄읽기().공백제거().나누기();    양 = 칸들[0].수로변환();    단위 = 1;    만약 (칸들[1] == "KB")    {        단위 = 킬로;    }    아니면 만약 (칸들[1] == "MB")    {        단위 = 메가;    }    아니면 만약 (칸들[1] == "GB")    {        단위 = 기가;    }    합 += 양 * 단위;} 묶음수 = 0;만약 (합 > 기본량){    묶음수 = 수학.몫(합 - 기본량 + 묶음 - 1, 묶음); // 올림}콘솔.쓰기(합);콘솔.쓰기(묶음수);콘솔.쓰기(묶음수 * 묶음요금);