{ }codelper
改行なし出力P0404

数字フォントで印刷する横断幕

数字の横断幕マシンは、入力で受け取ったフォントで数字の文字列を大きく印刷する。
フォントには 0 から 9 までの数字ごとに絵が一つずつある。
絵一つは h 行で、各行は # と . だけからなる文字列である。
一つの絵の行はすべて同じ長さで、この長さをその数字の幅と呼ぶ。
数字ごとに幅が違うことがある。
印刷する数字の文字列 s の数字を、左から順に塊に入れていく。
一つの塊の中では絵を左から並べ、隣り合う二つの絵の間に . だけからなる列を一つはさむ。
塊の幅は、中の絵の幅の合計にはさんだ列の数を足した値である。
s の最初の数字は最初の塊に入れる。
次の数字からは、今の塊に入れても塊の幅が W 以下なら今の塊に入れ、W を超えるなら新しい塊を始めてそこに入れる。
塊は作った順に出力する。
塊一つは h 行で出力し、その k 行目は塊の中の絵の k 行目を左から . を一つずつはさんでつないだものである。
したがって行の長さはその塊の幅と等しく、行の先頭と末尾にははさんだ . は来ない。
隣り合う二つの塊の間には空行を一つ出力する。
最初の塊の前と最後の塊の後には空行を出力しない。

入力
1 行目に絵の高さ h と塊の幅の上限 W が空白一つで区切って与えられる。
続く 10×h 行に、0 の絵、1 の絵、…、9 の絵が順に h 行ずつ与えられる。
最後の行に数字の文字列 s が与えられる。
1 ≤ h ≤ 8 である。
絵の幅は 1 以上 8 以下で、いちばん広い絵の幅 ≤ W ≤ 80 である。
したがって絵を一つだけ入れた塊が W を超えることはない。
s は数字 0~9 だけからなり、長さは 1 以上 1,000 以下である。
出力
塊ごとに h 行。
隣り合う塊の間に空行一つ
例 1 · stdin
3 7
###
#.#
###
#
#
#
##.
.#.
.##
###
.##
###
#.#
###
..#
.##
.#.
##.
#..
###
###
##
.#
.#
###
###
###
###
###
..#
01230
stdout
###.#
#.#.#
###.#

##..###
.#...##
.##.###

###
#.#
###
main.py
入力(stdin)

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

$ 準備完了

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

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

この問題では、一行を複数の絵のかけらで続けて書いてから改行します。
だから外側のループは行(0 ~ h-1)、内側のループは塊の中の絵です — 絵一つを h 行全部書いてから次の絵へ進むと、数字が横ではなく下に積み重なります。
改行せずに続けて書く方法は言語ごとに違います。
Python は print(x, end="")(ただの print(x) は末尾に \n を付けます)、JS・TS は process.stdout.write(x)(console.log は必ず改行します。
かけらごとに write を何万回も呼ぶと遅いので、解答は文字列につないでから一度に書きます)、Java は print と println(解答は速く書くために PrintWriter にためて最後に flush() します)、C# は Write と WriteLine、C は fputs・putchar・printf、C++ は std::cout << x(改行は '\n' を自分で入れます)、Craykon は コンソール.続けて書く(x) と コンソール.書く(x) です。
Craykon で改行だけしたいときは コンソール.書く("") を使います。
落とし穴一:改行する出力関数を使うこと。
Python の print(glyph[row]) や、C で fputs の代わりに puts を使うと(puts は末尾に改行を付けます)かけらごとに改行され、例の 1 行目から ### だけになります。
落とし穴二:絵ごとに後ろへ . を付けると、行末に . が一つ残ります(例の 1 行目が ###.#. になります)。
行末の空白は大目に見る採点機も多いですが、. は見える文字なのでそのまま不正解です。
最初の絵以外の前に . を付けます。
落とし穴三:塊の幅を間違えて測ること。
絵を入れたときに増える幅は、絵の幅にはさむ列の 1 を足した値です。
はさむ列を数えないと例で 0、1、2 が一つの塊(本当の幅は 9)に入り、≤ W の代わりに < W で比べると幅がちょうど 7 の二つ目の塊(2 と 3)が二つに割れます。
落とし穴四:空行は塊の間にだけ入れます。
忘れると塊同士がくっつき、塊ごとに前に入れると最初の行が空行になります。
二つ目の塊から前に空行を一つ入れます。

Pythonmain.py · 31 行
import sys tokens = sys.stdin.read().split()h, w_max = int(tokens[0]), int(tokens[1])font = []for d in range(10):    font.append(tokens[2 + d * h: 2 + (d + 1) * h])s = tokens[2 + 10 * h] # 숫자들을 덩어리로 나눈다blocks = []width = 0for ch in s:    glyph = font[int(ch)]    gw = len(glyph[0])    if blocks and width + 1 + gw <= w_max:        blocks[-1].append(glyph)        width += 1 + gw    else:        blocks.append([glyph])        width = gw for b, block in enumerate(blocks):    if b > 0:        print()    for row in range(h):        for i, glyph in enumerate(block):            if i > 0:                print(".", end="")            print(glyph[row], end="")        print()
JavaScriptmain.js · 35 行
const tokens = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);const h = Number(tokens[0]);const maxWidth = Number(tokens[1]);const font = [];for (let d = 0; d < 10; d++) font.push(tokens.slice(2 + d * h, 2 + (d + 1) * h));const s = tokens[2 + 10 * h]; // 숫자들을 덩어리로 나눈다const blocks = [];let width = 0;for (const ch of s) {  const glyph = font[Number(ch)];  const gw = glyph[0].length;  if (blocks.length > 0 && width + 1 + gw <= maxWidth) {    blocks[blocks.length - 1].push(glyph);    width += 1 + gw;  } else {    blocks.push([glyph]);    width = gw;  }} // console.log는 늘 줄을 바꾼다. 조각을 문자열에 이어 붙였다가 process.stdout.write로 한 번에 쓴다let out = "";blocks.forEach((block, b) => {  if (b > 0) out += "\n";  for (let row = 0; row < h; row++) {    block.forEach((glyph, i) => {      if (i > 0) out += ".";      out += glyph[row];    });    out += "\n";  }});process.stdout.write(out);
TypeScriptmain.ts · 36 行
import { readFileSync } from "node:fs";const tokens: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const h: number = Number(tokens[0]);const maxWidth: number = Number(tokens[1]);const font: string[][] = [];for (let d = 0; d < 10; d++) font.push(tokens.slice(2 + d * h, 2 + (d + 1) * h));const s: string = tokens[2 + 10 * h]; // 숫자들을 덩어리로 나눈다const blocks: string[][][] = [];let width = 0;for (const ch of s) {  const glyph = font[Number(ch)];  const gw = glyph[0].length;  if (blocks.length > 0 && width + 1 + gw <= maxWidth) {    blocks[blocks.length - 1].push(glyph);    width += 1 + gw;  } else {    blocks.push([glyph]);    width = gw;  }} // console.log는 늘 줄을 바꾼다. 조각을 문자열에 이어 붙였다가 process.stdout.write로 한 번에 쓴다let out: string = "";blocks.forEach((block, b) => {  if (b > 0) out += "\n";  for (let row = 0; row < h; row++) {    block.forEach((glyph, i) => {      if (i > 0) out += ".";      out += glyph[row];    });    out += "\n";  }});process.stdout.write(out);
JavaMain.java · 48 行
import java.io.*;import java.util.*; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int h = Integer.parseInt(st.nextToken());        int maxWidth = Integer.parseInt(st.nextToken());        String[][] font = new String[10][h];        for (int d = 0; d < 10; d++)            for (int r = 0; r < h; r++)                font[d][r] = in.readLine().trim();        String s = in.readLine().trim();         // 숫자들을 덩어리로 나눈다        List<List<String[]>> blocks = new ArrayList<>();        int width = 0;        for (char ch : s.toCharArray()) {            String[] glyph = font[ch - '0'];            int gw = glyph[0].length();            if (!blocks.isEmpty() && width + 1 + gw <= maxWidth) {                blocks.get(blocks.size() - 1).add(glyph);                width += 1 + gw;            } else {                List<String[]> block = new ArrayList<>();                block.add(glyph);                blocks.add(block);                width = gw;            }        }         // print는 줄을 바꾸지 않고, println은 바꾼다        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));        for (int b = 0; b < blocks.size(); b++) {            if (b > 0) out.println();            List<String[]> block = blocks.get(b);            for (int row = 0; row < h; row++) {                for (int i = 0; i < block.size(); i++) {                    if (i > 0) out.print('.');                    out.print(block.get(i)[row]);                }                out.println();            }        }        out.flush();    }}
C#Main.cs · 56 行
using System;using System.Collections.Generic;using System.IO; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int h = int.Parse(first[0]);        int maxWidth = int.Parse(first[1]);        var font = new string[10][];        for (int d = 0; d < 10; d++)        {            font[d] = new string[h];            for (int r = 0; r < h; r++) font[d][r] = Console.ReadLine().Trim();        }        string s = Console.ReadLine().Trim();         // 숫자들을 덩어리로 나눈다        var blocks = new List<List<string[]>>();        int width = 0;        foreach (char ch in s)        {            string[] glyph = font[ch - '0'];            int gw = glyph[0].Length;            if (blocks.Count > 0 && width + 1 + gw <= maxWidth)            {                blocks[^1].Add(glyph);                width += 1 + gw;            }            else            {                blocks.Add(new List<string[]> { glyph });                width = gw;            }        }         // Write는 줄을 바꾸지 않고, WriteLine은 바꾼다        var output = new StreamWriter(Console.OpenStandardOutput());        for (int b = 0; b < blocks.Count; b++)        {            if (b > 0) output.WriteLine();            for (int row = 0; row < h; row++)            {                for (int i = 0; i < blocks[b].Count; i++)                {                    if (i > 0) output.Write('.');                    output.Write(blocks[b][i][row]);                }                output.WriteLine();            }        }        output.Flush();    }}
C++main.cpp · 42 行
#include <iostream>#include <string>#include <vector>using namespace std; int main() {    int h, maxWidth;    cin >> h >> maxWidth;    vector<vector<string>> font(10, vector<string>(h));    for (int d = 0; d < 10; d++)        for (int r = 0; r < h; r++) cin >> font[d][r];    string s;    cin >> s;     // 숫자들을 덩어리로 나눈다    vector<vector<int>> blocks;    int width = 0;    for (char ch : s) {        int digit = ch - '0';        int gw = (int)font[digit][0].size();        if (!blocks.empty() && width + 1 + gw <= maxWidth) {            blocks.back().push_back(digit);            width += 1 + gw;        } else {            blocks.push_back({digit});            width = gw;        }    }     // cout << 는 줄을 바꾸지 않는다. 줄바꿈은 '\n'으로 직접 넣는다    for (size_t b = 0; b < blocks.size(); b++) {        if (b > 0) cout << '\n';        for (int row = 0; row < h; row++) {            for (size_t i = 0; i < blocks[b].size(); i++) {                if (i > 0) cout << '.';                cout << font[blocks[b][i]][row];            }            cout << '\n';        }    }    return 0;}
Cmain.c · 42 行
#include <stdio.h>#include <string.h> char font[10][8][9]; /* 숫자 10개 × 줄 8개 × (글자 8개 + '\0') */char s[1001];int blockStart[1001]; /* 덩어리마다 첫 숫자의 자리 */ int main(void) {    int h, maxWidth;    scanf("%d %d", &h, &maxWidth);    for (int d = 0; d < 10; d++)        for (int r = 0; r < h; r++)            scanf("%8s", font[d][r]);    scanf("%1000s", s);    int n = (int)strlen(s);     /* 숫자들을 덩어리로 나눈다 */    int blocks = 0, width = 0;    for (int i = 0; i < n; i++) {        int gw = (int)strlen(font[s[i] - '0'][0]);        if (blocks > 0 && width + 1 + gw <= maxWidth) {            width += 1 + gw;        } else {            blockStart[blocks++] = i;            width = gw;        }    }    blockStart[blocks] = n;     /* puts는 끝에 줄바꿈을 붙이므로 fputs·putchar로 이어 쓴다 */    for (int b = 0; b < blocks; b++) {        if (b > 0) putchar('\n');        for (int row = 0; row < h; row++) {            for (int i = blockStart[b]; i < blockStart[b + 1]; i++) {                if (i > blockStart[b]) putchar('.');                fputs(font[s[i] - '0'][row], stdout);            }            putchar('\n');        }    }    return 0;}
Craykonmain.cray · 55 行
첫줄 = コンソール.数読み();h = 첫줄[0];최대너비 = 첫줄[1];글꼴 = [];繰り返す (d = 0; d < 10; d++){    그림 = [];    繰り返す (r = 0; r < h; r++)    {        그림.追加(コンソール.行読み().空白除去());    }    글꼴.追加(그림);}s = コンソール.行読み().空白除去(); // 숫자들을 덩어리로 나눈다덩어리들 = [];너비 = 0;それぞれ (c の中 s){    숫자 = c.数に();    그림너비 = 글꼴[숫자][0].長さ;    もし (덩어리들.個数 > 0 && 너비 + 1 + 그림너비 <= 최대너비)    {        덩어리들[덩어리들.個数 - 1].追加(숫자);        너비 += 1 + 그림너비;    }    でなければ    {        덩어리들.追加([숫자]);        너비 = 그림너비;    }} // 콘솔.쓰기는 줄을 바꾸고, 콘솔.이어쓰기는 바꾸지 않는다繰り返す (b = 0; b < 덩어리들.個数; b++){    もし (b > 0)    {        コンソール.書く("");    }    덩어리 = 덩어리들[b];    繰り返す (줄 = 0; 줄 < h; 줄++)    {        繰り返す (i = 0; i < 덩어리.個数; i++)        {            もし (i > 0)            {                コンソール.続けて書く(".");            }            コンソール.続けて書く(글꼴[덩어리[i]][줄]);        }        コンソール.書く("");    }}