{ }codelper
건너뛰며 반복문자열 만들어 가기문자열 길이P0172

글자로 그린 자

글자로 자를 그려 출력한다. 첫 줄에 자의 길이 n과 큰 눈금 간격 k가 빈칸 하나로 띄어 주어진다. 자에는 0부터 n까지 n + 1개의 칸이 있고, 칸 번호는 왼쪽부터 0, 1, 2, …, n이다. 첫째 줄은 눈금 줄이다.
정확히 n + 1글자이고, 칸 c의 글자는 c가 k의 배수면 |, 아니면 .
이다. 둘째 줄은 숫자 줄이다.
0, k, 2k, 3k, …처럼 n 이하인 k의 배수 m을 작은 것부터 차례로 보며, m을 십진수로 칸 m부터 오른쪽으로 쓰려고 한다. m을 쓰면 차지하는 마지막 칸은 m + (m의 자릿수) − 1이다.
이 칸이 n보다 크면 m을 쓰지 않는다. 또 앞에서 이미 쓴 숫자가 있으면, 그 숫자의 마지막 칸과 칸 m 사이에 빈칸이 적어도 하나 있어야 한다.
그렇지 않으면 m을 쓰지 않는다. 쓰지 않고 건너뛴 숫자는 그 뒤의 판단에 아무 영향을 주지 않는다. 숫자를 쓰지 않은 칸은 빈칸이고, 숫자 줄의 맨 끝 빈칸은 출력하지 않는다. 셋째 줄에는 숫자 줄에 쓴 숫자의 개수를 출력한다.

입력
1 ≤ k ≤ n ≤ 5000
출력
세 줄
예시 1 · stdin
25 5
stdout
|....|....|....|....|....|
0    5    10   15   20
5
예시 2 · stdin
12 1
stdout
|||||||||||||
0 2 4 6 8 10
6
main.py
입력(stdin)

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

$ 준비됐어요

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

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

눈금은 k씩 건너뛰는 반복이에요.
Python range(0, n + 1, k)는 끝을 넣지 않아서 n + 1까지 줘야 칸 n이 들어가요.
나머지 언어는 for (m = 0; m <= n; m += k), 크레이콘은 반복 (m = 0; m <= n; m += k)예요.
눈금 줄을 c < n으로 돌면 n글자만 나와서 첫 예시의 맨 끝 | 가 빠져요.
숫자 줄은 왼쪽부터 차례로 붙여 가면 지금 길이가 곧 다음 빈 칸 번호라서, '빈칸이 하나 이상'은 m > 지금 길이, 모자란 빈칸은 m - 지금 길이개예요.
건너뛴 숫자의 끝 칸을 '앞 숫자'로 기억하면 두 번째 예시에서 2, 4, 6도 빠져요.
맞는지는 <=이라서 <로 쓰면 n = 9, k = 9의 9가 사라져요.
자릿수는 수를 문자열로 바꿔 길이를 재요.
Python len(str(m)), JS·TS String(m).length, Java Integer.toString(m).length(), C# m.ToString().Length, C++ std::to_string(m).size(), 크레이콘 ("" + m).길이예요.
C는 sprintf가 돌려주는 쓴 글자 수를 쓰면 돼요.
문자열을 이어 붙이는 방법도 달라요.
Java·C#은 반복문에서 +=를 하면 매번 새 문자열을 복사하니 StringBuilder를 써요(C#은 Append(' ', 개수)로 빈칸을 한 번에 붙여요).
Python·JS·TS·C++ std::string·크레이콘은 +=로 충분하고, C는 글자 배열에 채운 뒤 끝에 '\0'을 넣어요.
C++ size()는 부호 없는 수라서 m > labels.size()처럼 섞어 비교하기 전에 int로 바꿔 두는 게 안전해요.

Pythonmain.py · 19 줄
n, k = map(int, input().split()) # 눈금 줄: 칸 0 ~ n, 모두 n + 1글자marks = "".join("|" if c % k == 0 else "." for c in range(n + 1)) # 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다labels = ""count = 0for m in range(0, n + 1, k):    t = str(m)    fits = m + len(t) - 1 <= n             # 마지막 칸이 n을 넘지 않는다    gap = labels == "" or m > len(labels)  # 앞 숫자와 빈칸이 하나 이상 있다    if fits and gap:        labels += " " * (m - len(labels)) + t        count += 1 print(marks)print(labels)print(count)
JavaScriptmain.js · 19 줄
const [n, k] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자let marks = "";for (let c = 0; c <= n; c++) marks += c % k === 0 ? "|" : "."; // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다let labels = "";let count = 0;for (let m = 0; m <= n; m += k) {  const t = String(m);  const fits = m + t.length - 1 <= n; // 마지막 칸이 n을 넘지 않는다  const gap = labels === "" || m > labels.length; // 앞 숫자와 빈칸이 하나 이상 있다  if (fits && gap) {    labels += " ".repeat(m - labels.length) + t;    count++;  }}console.log([marks, labels, count].join("\n"));
TypeScriptmain.ts · 20 줄
import { readFileSync } from "node:fs";const [n, k]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자let marks = "";for (let c = 0; c <= n; c++) marks += c % k === 0 ? "|" : "."; // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다let labels = "";let count = 0;for (let m = 0; m <= n; m += k) {  const t: string = String(m);  const fits: boolean = m + t.length - 1 <= n; // 마지막 칸이 n을 넘지 않는다  const gap: boolean = labels === "" || m > labels.length; // 앞 숫자와 빈칸이 하나 이상 있다  if (fits && gap) {    labels += " ".repeat(m - labels.length) + t;    count++;  }}console.log([marks, labels, String(count)].join("\n"));
JavaMain.java · 28 줄
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt(), k = sc.nextInt();         // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자        StringBuilder marks = new StringBuilder();        for (int c = 0; c <= n; c++) marks.append(c % k == 0 ? '|' : '.');         // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다        StringBuilder labels = new StringBuilder();        int count = 0;        for (int m = 0; m <= n; m += k) {            String t = Integer.toString(m);            boolean fits = m + t.length() - 1 <= n; // 마지막 칸이 n을 넘지 않는다            boolean gap = labels.length() == 0 || m > labels.length(); // 앞 숫자와 빈칸이 하나 이상            if (fits && gap) {                labels.append(" ".repeat(m - labels.length())).append(t);                count++;            }        }        System.out.println(marks);        System.out.println(labels);        System.out.println(count);    }}
C#Main.cs · 33 줄
using System;using System.Text; class Program{    static void Main()    {        string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(p[0]), k = int.Parse(p[1]);         // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자        var marks = new StringBuilder();        for (int c = 0; c <= n; c++) marks.Append(c % k == 0 ? '|' : '.');         // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다        var labels = new StringBuilder();        int count = 0;        for (int m = 0; m <= n; m += k)        {            string t = m.ToString();            bool fits = m + t.Length - 1 <= n; // 마지막 칸이 n을 넘지 않는다            bool gap = labels.Length == 0 || m > labels.Length; // 앞 숫자와 빈칸이 하나 이상            if (fits && gap)            {                labels.Append(' ', m - labels.Length).Append(t);                count++;            }        }        Console.WriteLine(marks);        Console.WriteLine(labels);        Console.WriteLine(count);    }}
C++main.cpp · 26 줄
#include <iostream>#include <string> int main() {    int n, k;    std::cin >> n >> k;     // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자    std::string marks;    for (int c = 0; c <= n; c++) marks += c % k == 0 ? '|' : '.';     // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다    std::string labels;    int count = 0;    for (int m = 0; m <= n; m += k) {        std::string t = std::to_string(m);        int len = static_cast<int>(labels.size()); // size()는 부호 없는 수라 int로 바꿔 비교한다        bool fits = m + static_cast<int>(t.size()) - 1 <= n; // 마지막 칸이 n을 넘지 않는다        bool gap = len == 0 || m > len;                      // 앞 숫자와 빈칸이 하나 이상 있다        if (fits && gap) {            labels += std::string(m - len, ' ') + t;            count++;        }    }    std::cout << marks << '\n' << labels << '\n' << count << '\n';}
Cmain.c · 33 줄
#include <stdio.h>#include <string.h> #define MAXN 5000 int main(void) {    int n, k;    scanf("%d %d", &n, &k);     /* 눈금 줄: 칸 0 ~ n, 모두 n + 1글자 */    static char marks[MAXN + 2];    for (int c = 0; c <= n; c++) marks[c] = c % k == 0 ? '|' : '.';    marks[n + 1] = '\0';     /* 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다 */    static char labels[MAXN + 2];    int len = 0, count = 0;    char t[8];    for (int m = 0; m <= n; m += k) {        int w = sprintf(t, "%d", m);          /* sprintf는 쓴 글자 수를 돌려준다 */        int fits = m + w - 1 <= n;            /* 마지막 칸이 n을 넘지 않는다 */        int gap = len == 0 || m > len;        /* 앞 숫자와 빈칸이 하나 이상 있다 */        if (fits && gap) {            while (len < m) labels[len++] = ' ';            memcpy(labels + len, t, w);            len += w;            count++;        }    }    labels[len] = '\0';    printf("%s\n%s\n%d\n", marks, labels, count);    return 0;}
Craykonmain.cray · 35 줄
v = 콘솔.수들읽기();n = v[0];k = v[1]; // 눈금 줄: 칸 0 ~ n, 모두 n + 1글자눈금 = "";반복 (c = 0; c <= n; c += 1){    만약 (c % k == 0)    {        눈금 += "|";    }    아니면    {        눈금 += ".";    }} // 숫자 줄: 0, k, 2k, ... 를 차례로 보며 쓸 수 있는 것만 뒤에 붙인다숫자줄 = "";개수 = 0;반복 (m = 0; m <= n; m += k){    t = "" + m;    맞음 = m + t.길이 - 1 <= n; // 마지막 칸이 n을 넘지 않는다    띄움 = 숫자줄 == "" || m > 숫자줄.길이; // 앞 숫자와 빈칸이 하나 이상 있다    만약 (맞음 && 띄움)    {        숫자줄 += " ".되풀이(m - 숫자줄.길이) + t;        개수 += 1;    }}콘솔.쓰기(눈금);콘솔.쓰기(숫자줄);콘솔.쓰기(개수);