{ }codelper
累積条件分岐64ビット整数P0137

累進税率で所得税を計算

人ごとに一年の所得と控除人数 k が与えられる。
課税標準は所得から 1,500,000 × k を引いた値で、0 より小さければ 0 とする。
税金は課税標準を下の区間に分け、区間に入る部分ごとにその区間の税率を掛けてすべて足す。
14,000,000 ウォン以下の部分は 6% である。
14,000,000 ウォン超 50,000,000 ウォン以下の部分は 15% である。
50,000,000 ウォン超 88,000,000 ウォン以下の部分は 24% である。
88,000,000 ウォン超 150,000,000 ウォン以下の部分は 35% である。
150,000,000 ウォン超 300,000,000 ウォン以下の部分は 38% である。
300,000,000 ウォン超 500,000,000 ウォン以下の部分は 40% である。
500,000,000 ウォン超 1,000,000,000 ウォン以下の部分は 42% である。
1,000,000,000 ウォンを超える部分は 45% である。
こうして足した値をウォン単位で切り捨てたものが算出税額 T である(区間ごとに切り捨てず、すべて足してから一度だけ切り捨てる)。
次に税額控除 C を決める。
T が 1,300,000 以下なら、C は T × 55 / 100 を切り捨てた値である。
T が 1,300,000 を超えるなら、C は 715,000 に (T − 1,300,000) × 30 / 100 を切り捨てた値を足したものだが、740,000 を超えれば 740,000 とする。
納める税額は T − C である。
限界税率は課税標準の最後の 1 ウォンが入る区間の税率(%)で、課税標準が 0 なら 0 である。
課税標準が区間の上端と等しければ、その区間に入るとみなす。
一行目に人数 n が与えられ、続く n 行に人ごとの所得と k が空白一つを挟んで与えられる。
人ごとに一行に T、納める税額、限界税率(% 記号を付けず数だけ)を空白一つずつ区切って、入力の順に出力せよ。

入力
1 ≤ n ≤ 1,000、0 ≤ 所得 ≤ 100,000,000,000、1 ≤ k ≤ 20、すべて整数
出力
n 行、各行に整数三つ:算出税額、納める税額、限界税率
例 1 · stdin
3
60000000 3
15500000 1
3000000 2
stdout
7560000 6820000 24
840000 378000 6
0 0 0
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

累進税は「区間を順に回り、その区間に入る分だけ積み上げていく」ループです。
if (base <= low) break; で課税標準が区間の下端を超えなければ止まり、超えれば min(base, high) - low に税率を掛けて足します。
課税標準全体に最後の区間の税率を掛けるのがいちばん多い間違いです(例の 55,500,000 ウォンなら 13,320,000 ウォンになります)。
<= の代わりに < で止めると、課税標準がちょうど 14,000,000 ウォンのとき限界税率が 15 に変わります。
積み上げる値は最大約 4.5 兆なので int(約 21 億)に入りません:C・C++ long long(printf は %lld)、Java・C# long、リテラルも 1_500_000L * k のように long で掛けます。
Python の整数は大きさに制限がなく、JS・TS・Craykon は数が一つ(double)ですが 2^53(約 9 × 10^15)の中なので正確です。
税率を 0.35 のような実数で掛けて切り捨てると、二進実数の誤差で 1 ウォン足りなくなることがあります:180 * 0.35 は 63 ではなく 62.99999999999999 なので、課税標準 88,000,180 ウォンの 35% の部分を区間ごとに切り捨てると 62 ウォンになります。
そこでパーセントの整数を掛けて積み上げ、100 では最後に一度だけ整数の割り算で割ります:Python //、C 系の整数 /、JS・TS Math.floor(a / 100)、Craykon 数学.商(a, 100)。
控除は二つに分かれる if-else です:Python if … else:、Craykon もし … でなければ。
上限 740,000 ウォンは min でもう一度押さえます。

Pythonmain.py · 37 行
import sys # (구간 아래 끝, 위 끝, 세율 %) — 아래 끝 초과 위 끝 이하인 부분에 그 세율BRACKETS = [    (0, 14_000_000, 6),    (14_000_000, 50_000_000, 15),    (50_000_000, 88_000_000, 24),    (88_000_000, 150_000_000, 35),    (150_000_000, 300_000_000, 38),    (300_000_000, 500_000_000, 40),    (500_000_000, 1_000_000_000, 42),    (1_000_000_000, 10**18, 45),] data = sys.stdin.read().split()n = int(data[0])out = []for i in range(n):    income = int(data[1 + 2 * i])    k = int(data[2 + 2 * i])    base = max(income - 1_500_000 * k, 0)     total = 0  # 세율을 곱한 값을 쌓는다(100으로는 마지막에 한 번 나눈다)    rate = 0    for low, high, r in BRACKETS:        if base <= low:            break        total += (min(base, high) - low) * r        rate = r    tax = total // 100     if tax <= 1_300_000:        credit = tax * 55 // 100    else:        credit = min(715_000 + (tax - 1_300_000) * 30 // 100, 740_000)    out.append(f"{tax} {tax - credit} {rate}")print("\n".join(out))
JavaScriptmain.js · 39 行
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // [구간 아래 끝, 위 끝, 세율 %] — 아래 끝 초과 위 끝 이하인 부분에 그 세율const BRACKETS = [  [0, 14000000, 6],  [14000000, 50000000, 15],  [50000000, 88000000, 24],  [88000000, 150000000, 35],  [150000000, 300000000, 38],  [300000000, 500000000, 40],  [500000000, 1000000000, 42],  [1000000000, Infinity, 45],]; const n = data[0];const out = [];for (let i = 0; i < n; i++) {  const income = data[1 + 2 * i];  const k = data[2 + 2 * i];  const base = Math.max(income - 1500000 * k, 0);   let total = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 2^53 안에서 정확)  let rate = 0;  for (const [low, high, r] of BRACKETS) {    if (base <= low) break;    total += (Math.min(base, high) - low) * r;    rate = r;  }  const tax = Math.floor(total / 100);   let credit;  if (tax <= 1300000) {    credit = Math.floor((tax * 55) / 100);  } else {    credit = Math.min(715000 + Math.floor(((tax - 1300000) * 30) / 100), 740000);  }  out.push(`${tax} ${tax - credit} ${rate}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 40 行
import { readFileSync } from "node:fs";const data: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // [구간 아래 끝, 위 끝, 세율 %] — 아래 끝 초과 위 끝 이하인 부분에 그 세율const BRACKETS: [number, number, number][] = [  [0, 14000000, 6],  [14000000, 50000000, 15],  [50000000, 88000000, 24],  [88000000, 150000000, 35],  [150000000, 300000000, 38],  [300000000, 500000000, 40],  [500000000, 1000000000, 42],  [1000000000, Infinity, 45],]; const n: number = data[0];const out: string[] = [];for (let i = 0; i < n; i++) {  const income: number = data[1 + 2 * i];  const k: number = data[2 + 2 * i];  const base: number = Math.max(income - 1500000 * k, 0);   let total = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 2^53 안에서 정확)  let rate = 0;  for (const [low, high, r] of BRACKETS) {    if (base <= low) break;    total += (Math.min(base, high) - low) * r;    rate = r;  }  const tax: number = Math.floor(total / 100);   let credit: number;  if (tax <= 1300000) {    credit = Math.floor((tax * 55) / 100);  } else {    credit = Math.min(715000 + Math.floor(((tax - 1300000) * 30) / 100), 740000);  }  out.push(`${tax} ${tax - credit} ${rate}`);}console.log(out.join("\n"));
JavaMain.java · 41 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    // 구간 아래 끝과 세율 % — 아래 끝 초과 다음 아래 끝 이하인 부분에 그 세율    static final long[] LOW = {0L, 14_000_000L, 50_000_000L, 88_000_000L, 150_000_000L, 300_000_000L, 500_000_000L, 1_000_000_000L};    static final int[] RATE = {6, 15, 24, 35, 38, 40, 42, 45};     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            long income = Long.parseLong(st.nextToken());            int k = Integer.parseInt(st.nextToken());            long base = Math.max(income - 1_500_000L * k, 0L);             long total = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 int로는 넘친다)            int rate = 0;            for (int b = 0; b < LOW.length; b++) {                if (base <= LOW[b]) break;                long high = b + 1 < LOW.length ? LOW[b + 1] : Long.MAX_VALUE;                total += (Math.min(base, high) - LOW[b]) * RATE[b];                rate = RATE[b];            }            long tax = total / 100;             long credit;            if (tax <= 1_300_000) {                credit = tax * 55 / 100;            } else {                credit = Math.min(715_000 + (tax - 1_300_000) * 30 / 100, 740_000);            }            out.append(tax).append(' ').append(tax - credit).append(' ').append(rate).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 45 行
using System;using System.Text; class Program{    // 구간 아래 끝과 세율 % — 아래 끝 초과 다음 아래 끝 이하인 부분에 그 세율    static readonly long[] Low = { 0L, 14_000_000L, 50_000_000L, 88_000_000L, 150_000_000L, 300_000_000L, 500_000_000L, 1_000_000_000L };    static readonly int[] Rate = { 6, 15, 24, 35, 38, 40, 42, 45 };     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            long income = long.Parse(p[0]);            int k = int.Parse(p[1]);            long baseAmount = Math.Max(income - 1_500_000L * k, 0L);             long total = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 int로는 넘친다)            int rate = 0;            for (int b = 0; b < Low.Length; b++)            {                if (baseAmount <= Low[b]) break;                long high = b + 1 < Low.Length ? Low[b + 1] : long.MaxValue;                total += (Math.Min(baseAmount, high) - Low[b]) * Rate[b];                rate = Rate[b];            }            long tax = total / 100;             long credit;            if (tax <= 1_300_000)            {                credit = tax * 55 / 100;            }            else            {                credit = Math.Min(715_000 + (tax - 1_300_000) * 30 / 100, 740_000);            }            sb.Append(tax).Append(' ').Append(tax - credit).Append(' ').Append(rate).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 36 行
#include <algorithm>#include <array>#include <iostream>#include <limits> int main() {    // 구간 아래 끝과 세율 % — 아래 끝 초과 다음 아래 끝 이하인 부분에 그 세율    const std::array<long long, 8> low = {0LL, 14000000LL, 50000000LL, 88000000LL, 150000000LL, 300000000LL, 500000000LL, 1000000000LL};    const std::array<int, 8> rates = {6, 15, 24, 35, 38, 40, 42, 45};    int n;    std::cin >> n;    for (int i = 0; i < n; i++) {        long long income;        int k;        std::cin >> income >> k;        long long base = std::max(income - 1500000LL * k, 0LL);         long long total = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 int로는 넘친다)        int rate = 0;        for (int b = 0; b < 8; b++) {            if (base <= low[b]) break;            long long high = b + 1 < 8 ? low[b + 1] : std::numeric_limits<long long>::max();            total += (std::min(base, high) - low[b]) * rates[b];            rate = rates[b];        }        long long tax = total / 100;         long long credit;        if (tax <= 1300000) {            credit = tax * 55 / 100;        } else {            credit = std::min(715000 + (tax - 1300000) * 30 / 100, 740000LL);        }        std::cout << tax << ' ' << tax - credit << ' ' << rate << '\n';    }}
Cmain.c · 38 行
#include <stdio.h> /* 구간 아래 끝과 세율 % — 아래 끝 초과 다음 아래 끝 이하인 부분에 그 세율 */static const long long LOW[8] = {0LL, 14000000LL, 50000000LL, 88000000LL, 150000000LL, 300000000LL, 500000000LL, 1000000000LL};static const int RATE[8] = {6, 15, 24, 35, 38, 40, 42, 45}; int main(void) {    int n;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        long long income;        int k;        scanf("%lld %d", &income, &k);        long long base = income - 1500000LL * k;        if (base < 0) base = 0;         long long total = 0; /* 세율을 곱한 값을 쌓는다(최대 약 4.5조라 int로는 넘친다) */        int rate = 0;        for (int b = 0; b < 8; b++) {            if (base <= LOW[b]) break;            long long top = base;            if (b + 1 < 8 && LOW[b + 1] < top) top = LOW[b + 1];            total += (top - LOW[b]) * RATE[b];            rate = RATE[b];        }        long long tax = total / 100;         long long credit;        if (tax <= 1300000) {            credit = tax * 55 / 100;        } else {            credit = 715000 + (tax - 1300000) * 30 / 100;            if (credit > 740000) credit = 740000;        }        printf("%lld %lld %d\n", tax, tax - credit, rate);    }    return 0;}
Craykonmain.cray · 41 行
// 구간 아래 끝과 세율 % — 아래 끝 초과 다음 아래 끝 이하인 부분에 그 세율아래끝 = [0, 14000000, 50000000, 88000000, 150000000, 300000000, 500000000, 1000000000];세율 = [6, 15, 24, 35, 38, 40, 42, 45]; n = コンソール.行読み().数に();繰り返す (i = 0; i < n; i++){    p = コンソール.数読み();    소득 = p[0];    k = p[1];    과세표준 = 数学.大きい方(소득 - 1500000 * k, 0);     합 = 0; // 세율을 곱한 값을 쌓는다(최대 약 4.5조라 2^53 안에서 정확)    한계세율 = 0;    繰り返す (b = 0; b < 8; b++)    {        もし (과세표준 <= 아래끝[b])        {            抜ける;        }        위끝 = 과세표준;        もし (b + 1 < 8)        {            위끝 = 数学.小さい方(과세표준, 아래끝[b + 1]);        }        합 += (위끝 - 아래끝[b]) * 세율[b];        한계세율 = 세율[b];    }    세액 = 数学.商(합, 100);     공제 = 0;    もし (세액 <= 1300000)    {        공제 = 数学.商(세액 * 55, 100);    }    でなければ    {        공제 = 数学.小さい方(715000 + 数学.商((세액 - 1300000) * 30, 100), 740000);    }    コンソール.書く(세액 + " " + (세액 - 공제) + " " + 한계세율);}