[0]zero-index clytie0x/zero-index

8.6 แบบฝึกหัด

เขียนแต่ละข้อเป็นไฟล์ใหม่ใน Code::Blocks รันแล้วเทียบกับผลลัพธ์ที่ต้องได้ให้ตรงทุกตัวอักษร รวมถึงช่องว่างและการขึ้นบรรทัด ติดจริงๆ ค่อยเปิดคำใบ้ และเปิดเฉลยหลังทำเสร็จแล้วเท่านั้น

ข้อ 1 ป้ายชื่อมีกรอบ

ระดับง่าย เวลาไม่เกิน 1 วินาที

ร้านป้ายหน้าโรงเรียนรับทำป้ายชื่อติดโต๊ะ ป้ายทุกแผ่นมีกรอบเป็นเครื่องหมาย # ล้อมรอบชื่อ และเว้นที่ว่างระหว่างกรอบกับชื่อ P ช่องทุกด้าน ทั้งซ้าย ขวา บน และล่าง ให้เขียนโปรแกรมพิมพ์ป้ายของชื่อ S

ถ้าชื่อยาว L ตัวอักษร ป้ายจะกว้าง L + 2P + 2 ตัวอักษร และสูง 2P + 3 บรรทัด ดังนี้

  • บรรทัดแรกและบรรทัดสุดท้ายเป็น # เต็มความกว้าง
  • P บรรทัดถัดจากบรรทัดแรก และ P บรรทัดก่อนบรรทัดสุดท้าย ขึ้นต้นและลงท้ายด้วย # ตรงกลางเป็นช่องว่างทั้งหมด
  • บรรทัดกลางขึ้นต้นด้วย # ตามด้วยช่องว่าง P ช่อง ชื่อ S ช่องว่าง P ช่อง และ #

ข้อมูลเข้า

บรรทัดเดียว มีชื่อ S และจำนวนเต็ม P คั่นด้วยช่องว่าง S ประกอบด้วยตัวอักษรภาษาอังกฤษหรือตัวเลขเท่านั้น ยาว 1 ถึง 50 ตัว และ 0 ≤ P ≤ 5

ข้อมูลออก

ป้ายชื่อ 2P + 3 บรรทัด ตามรูปแบบข้างบน

POSN 1
########
#      #
# POSN #
#      #
########
Ann 0
#####
#Ann#
#####
ดูคำใบ้

ป้ายมีบรรทัดแค่สามแบบ คือบรรทัดขอบ บรรทัดว่าง และบรรทัดชื่อ เขียน print_repeat(char symbol, int count) แบบ print_row ในหน้า 8.1 ก่อน แล้วสร้าง print_border(int width) กับ print_blank(int width) จากมัน main จะเหลือแค่เรียกฟังก์ชันตามลำดับบรรทัด ลองกับ P = 0 ด้วย ป้ายต้องเหลือแค่สามบรรทัด

ดูเฉลย
#include <stdio.h>
#include <string.h>

char name[55];

void print_repeat(char symbol, int count)
{
    for (int i = 0; i < count; i++) {
        printf("%c", symbol);
    }
}

void print_border(int width)
{
    print_repeat('#', width);
    printf("\n");
}

void print_blank(int width)
{
    printf("#");
    print_repeat(' ', width - 2);
    printf("#\n");
}

int main()
{
    int padding;
    scanf("%s %d", name, &padding);
    int width = strlen(name) + 2 * padding + 2;
    print_border(width);
    for (int i = 0; i < padding; i++) {
        print_blank(width);
    }
    printf("#");
    print_repeat(' ', padding);
    printf("%s", name);
    print_repeat(' ', padding);
    printf("#\n");
    for (int i = 0; i < padding; i++) {
        print_blank(width);
    }
    print_border(width);
    return 0;
}

ข้อ 2 ตั๋วผลบวกหลักสูงสุด

ระดับง่าย เวลาไม่เกิน 1 วินาที

งานวัดแจกตั๋วจับรางวัล N ใบ ตั๋วแต่ละใบมีเลขเป็นจำนวนเต็ม กติกาคือเอาเลขโดดทุกหลักของเลขบนตั๋วมาบวกกัน ใบที่ได้ผลบวกมากที่สุดเป็นผู้ชนะ เช่น ตั๋วเลข 4096 ได้ 4 + 0 + 9 + 6 = 19 ถ้ามีหลายใบที่ได้ผลบวกมากที่สุดเท่ากัน ใบที่มีเลขน้อยที่สุดเป็นผู้ชนะ ตั๋วหลายใบอาจมีเลขซ้ำกันได้

ให้หาเลขบนตั๋วที่ชนะ และผลบวกเลขโดดของตั๋วใบนั้น

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 100000

บรรทัดที่สองมีเลขบนตั๋ว N ใบ คั่นด้วยช่องว่าง แต่ละเลขเป็นจำนวนเต็มตั้งแต่ 0 ถึง 1000000000

ข้อมูลออก

บรรทัดเดียว มีเลขบนตั๋วที่ชนะ และผลบวกเลขโดดของตั๋วใบนั้น คั่นด้วยช่องว่าง

5
4096 512 77 1999 30
1999 28
4
2899 45 1999 600
1999 28
ดูคำใบ้

เขียน int digit_sum(int n) ที่ใช้ % 10 กับ /= 10 แบบหน้า 4.5 แล้ว main ทำแค่หาค่ามากสุดแบบหน้า 5.2 โดยเก็บทั้งเลขตั๋วและผลบวกของใบที่ดีที่สุดไว้ ตอนผลบวกเท่ากัน ต้องเทียบเลขตั๋วด้วย ใบที่มาก่อนไม่ได้ชนะเสมอไป และอย่าลืมตั๋วเลข 0 ซึ่งผลบวกเป็น 0

ดูเฉลย
#include <stdio.h>

int digit_sum(int n)
{
    int sum = 0;
    while (n > 0) {
        sum += n % 10;
        n /= 10;
    }
    return sum;
}

int main()
{
    int n;
    scanf("%d", &n);
    int best_ticket = -1;
    int best_sum = -1;
    for (int i = 0; i < n; i++) {
        int ticket;
        scanf("%d", &ticket);
        int sum = digit_sum(ticket);
        if (sum > best_sum || (sum == best_sum && ticket < best_ticket)) {
            best_ticket = ticket;
            best_sum = sum;
        }
    }
    printf("%d %d\n", best_ticket, best_sum);
    return 0;
}

ข้อ 3 วิ่งรอบสวน

ระดับง่าย เวลาไม่เกิน 1 วินาที

ทุกเย็นน้องวิ่งรอบสวนสาธารณะ โดยวิ่งผ่านจุดพัก N จุดตามลำดับ เริ่มจากจุดที่ 1 ไปจุดที่ 2 จุดที่ 3 จนถึงจุดที่ N แล้ววิ่งกลับมาที่จุดที่ 1 อีกครั้งเพื่อจบรอบ ระหว่างสองจุดวิ่งเป็นเส้นตรงเสมอ จุดแต่ละจุดบอกเป็นพิกัด (x, y) หน่วยเป็นเมตร ระยะระหว่างจุด (x1, y1) กับ (x2, y2) คือรากที่สองของ (x2 - x1)2 + (y2 - y1)2

ให้หาระยะทางรวมของหนึ่งรอบ และระยะของช่วงที่ยาวที่สุดในรอบนั้น ช่วงหนึ่งคือการวิ่งจากจุดหนึ่งไปจุดถัดไป รวมถึงช่วงสุดท้ายที่วิ่งจากจุดที่ N กลับมาจุดที่ 1 ถ้ามีจุดเดียว น้องยืนอยู่กับที่ ระยะทั้งสองเป็น 0

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

อีก N บรรทัดต่อมา บรรทัดที่ i มีจำนวนเต็ม x และ y ของจุดที่ i คั่นด้วยช่องว่าง โดยที่ -10000 ≤ x, y ≤ 10000 จุดหลายจุดอาจอยู่ที่เดียวกันได้

ข้อมูลออก

บรรทัดแรกพิมพ์ระยะทางรวมของหนึ่งรอบ บรรทัดที่สองพิมพ์ระยะของช่วงที่ยาวที่สุด ทั้งสองค่าเป็นทศนิยม 2 ตำแหน่ง

4
0 0
3 0
3 4
0 4
14.00
4.00
3
0 0
5 2
1 6
17.12
6.08
ดูคำใบ้

เก็บพิกัดไว้ในอาเรย์ แล้วเขียน double distance(int x1, int y1, int x2, int y2) แบบหน้า 8.5 จุดถัดจากจุดที่ i คือจุดที่ i + 1 ยกเว้นจุดสุดท้ายที่ต้องกลับไปจุดแรก ใช้ (i + 1) % n จะได้ตำแหน่งถัดไปแบบวนรอบโดยไม่ต้องแยกกรณี อย่าลืมช่วงขากลับ ตัวอย่างแรกมีช่วงขากลับยาว 4 เมตร และพิมพ์ด้วย %.2f

ดูเฉลย
#include <stdio.h>
#include <math.h>

int xs[1000];
int ys[1000];

double distance(int x1, int y1, int x2, int y2)
{
    double dx = x2 - x1;
    double dy = y2 - y1;
    return sqrt(dx * dx + dy * dy);
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &xs[i], &ys[i]);
    }
    double total = 0;
    double longest = 0;
    for (int i = 0; i < n; i++) {
        int next = (i + 1) % n;
        double leg = distance(xs[i], ys[i], xs[next], ys[next]);
        total += leg;
        if (leg > longest) {
            longest = leg;
        }
    }
    printf("%.2f\n", total);
    printf("%.2f\n", longest);
    return 0;
}

ข้อ 4 จำนวนเฉพาะกลับหลัง

ระดับง่าย เวลาไม่เกิน 1 วินาที

จำนวนเฉพาะคือจำนวนเต็มที่มากกว่า 1 และมีตัวหารที่เป็นจำนวนเต็มบวกแค่ 1 กับตัวมันเอง ครูคณิตศาสตร์ชอบจำนวนเฉพาะแบบพิเศษ คือจำนวนเฉพาะที่พอเขียนกลับหลังแล้วยังเป็นจำนวนเฉพาะอยู่ เช่น 13 กลับหลังได้ 31 ซึ่งเป็นจำนวนเฉพาะทั้งคู่ 11 กลับหลังได้ 11 ตัวเดิมก็นับ แต่ 19 กลับหลังได้ 91 = 7 × 13 ไม่นับ และ 91 เองก็ไม่นับเพราะไม่ใช่จำนวนเฉพาะ

เวลากลับหลัง ถ้ามีเลข 0 นำหน้าให้ตัดทิ้ง เช่น 1201 กลับหลังได้ 1021 ส่วน 3700 กลับหลังได้ 73

ให้นับว่าตั้งแต่ A ถึง B (รวม A และ B) มีจำนวนเต็ม n กี่ตัว ที่ n เป็นจำนวนเฉพาะ และ n ที่กลับหลังแล้วก็เป็นจำนวนเฉพาะด้วย

ข้อมูลเข้า

บรรทัดเดียว มีจำนวนเต็ม A และ B คั่นด้วยช่องว่าง โดยที่ 1 ≤ A ≤ B ≤ 100000

ข้อมูลออก

จำนวนของ n ที่ตรงเงื่อนไข

1 20
7
90 200
13
ดูคำใบ้

แยกเป็นสองฟังก์ชัน is_prime(n) แบบหน้า 8.5 และ reverse_number(n) ที่หยิบหลักขวาสุดด้วย % 10 มาต่อท้ายผลด้วย result * 10 + digit ทีละหลัก เลข 0 นำหน้าจะหายไปเอง แล้ว main เหลือเงื่อนไขเดียว is_prime(n) && is_prime(reverse_number(n)) ระวัง 1 ซึ่งไม่ใช่จำนวนเฉพาะ

ดูเฉลย
#include <stdio.h>

int is_prime(int n)
{
    if (n < 2) {
        return 0;
    }
    for (long long i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

int reverse_number(int n)
{
    int result = 0;
    while (n > 0) {
        result = result * 10 + n % 10;
        n /= 10;
    }
    return result;
}

int main()
{
    int a, b;
    scanf("%d %d", &a, &b);
    int count = 0;
    for (int n = a; n <= b; n++) {
        if (is_prime(n) && is_prime(reverse_number(n))) {
            count++;
        }
    }
    printf("%d\n", count);
    return 0;
}

ข้อ 5 ห้องไหนเก่งกว่า

ระดับกลาง เวลาไม่เกิน 1 วินาที

ม.3/1 กับ ม.3/2 สอบคณิตศาสตร์ข้อสอบชุดเดียวกัน ห้อง A มีนักเรียน N คน ห้อง B มีนักเรียน M คน ครูอยากเทียบสองห้อง โดยดูคะแนนสูงสุดและต่ำสุดของแต่ละห้อง แล้วดูว่าห้องไหนมีคะแนนเฉลี่ยสูงกว่า

คะแนนเฉลี่ยของห้องคือผลรวมคะแนนของทุกคนในห้องหารด้วยจำนวนคนในห้อง โดยไม่ปัดเศษ

ข้อมูลเข้า

บรรทัดที่ 1 มีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 1000

บรรทัดที่ 2 มีคะแนนของนักเรียนห้อง A ทั้ง N คน คั่นด้วยช่องว่าง

บรรทัดที่ 3 มีจำนวนเต็ม M โดยที่ 1 ≤ M ≤ 1000

บรรทัดที่ 4 มีคะแนนของนักเรียนห้อง B ทั้ง M คน คั่นด้วยช่องว่าง

คะแนนทุกค่าเป็นจำนวนเต็มตั้งแต่ 0 ถึง 100

ข้อมูลออก

บรรทัดที่ 1 พิมพ์คะแนนสูงสุดและต่ำสุดของห้อง A คั่นด้วยช่องว่าง

บรรทัดที่ 2 พิมพ์คะแนนสูงสุดและต่ำสุดของห้อง B คั่นด้วยช่องว่าง

บรรทัดที่ 3 พิมพ์ A ถ้าห้อง A มีคะแนนเฉลี่ยสูงกว่า พิมพ์ B ถ้าห้อง B สูงกว่า หรือพิมพ์ SAME ถ้าเท่ากันพอดี

5
62 88 75 91 70
4
80 95 95 60
91 62
95 60
B
2
1 2
1
1
2 1
1 1
A
ดูคำใบ้

งานเดียวกันทำกับสองห้อง จึงเขียนฟังก์ชันที่รับอาเรย์กับความยาวแบบหน้า 8.3 ชุดเดียว คือ read_array max_of_array min_of_array sum_of_array แล้วเรียกห้องละครั้ง ส่วนการเทียบค่าเฉลี่ย ถ้าหาร int ด้วย int จะตัดเศษทิ้ง ค่าเฉลี่ย 1.5 กับ 1 จะกลายเป็นเท่ากัน ให้ใช้วิธีเลี่ยงการหารในหน้า 5.2 คือเทียบ sumA × M กับ sumB × N แทน

ดูเฉลย
#include <stdio.h>

int room_a[1000];
int room_b[1000];

void read_array(int values[], int n)
{
    for (int i = 0; i < n; i++) {
        scanf("%d", &values[i]);
    }
}

int max_of_array(int values[], int n)
{
    int best = values[0];
    for (int i = 1; i < n; i++) {
        if (values[i] > best) {
            best = values[i];
        }
    }
    return best;
}

int min_of_array(int values[], int n)
{
    int worst = values[0];
    for (int i = 1; i < n; i++) {
        if (values[i] < worst) {
            worst = values[i];
        }
    }
    return worst;
}

int sum_of_array(int values[], int n)
{
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += values[i];
    }
    return sum;
}

int main()
{
    int n, m;
    scanf("%d", &n);
    read_array(room_a, n);
    scanf("%d", &m);
    read_array(room_b, m);
    printf("%d %d\n", max_of_array(room_a, n), min_of_array(room_a, n));
    printf("%d %d\n", max_of_array(room_b, m), min_of_array(room_b, m));
    int left = sum_of_array(room_a, n) * m;
    int right = sum_of_array(room_b, m) * n;
    if (left > right) {
        printf("A\n");
    } else if (left < right) {
        printf("B\n");
    } else {
        printf("SAME\n");
    }
    return 0;
}

ข้อ 6 รวมสูตรขนม

ระดับกลาง เวลาไม่เกิน 1 วินาที

สูตรขนมของคุณยายเขียนปริมาณวัตถุดิบเป็นเศษส่วนของถ้วยตวงทั้งหมด เช่น แป้ง 3/4 ถ้วย น้ำตาล 1/3 ถ้วย กะทิ 5/6 ถ้วย หลานอยากรู้ว่าวัตถุดิบทั้ง N อย่างรวมกันเป็นกี่ถ้วย โดยตอบเป็นเศษส่วนอย่างต่ำ

เศษส่วนอย่างต่ำ p/q คือเศษส่วนที่ p กับ q ไม่มีตัวหารร่วมอื่นนอกจาก 1 เช่น 6/4 ต้องตอบเป็น 3/2 ถ้าผลรวมเป็นจำนวนเต็มพอดี ให้ตอบเป็นจำนวนเต็มเฉยๆ เช่น 2/1 ให้ตอบ 2

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม N โดยที่ 1 ≤ N ≤ 20

อีก N บรรทัดต่อมา บรรทัดละหนึ่งเศษส่วนในรูป a/b ไม่มีช่องว่าง โดยที่ 1 ≤ a ≤ 1000 และ 1 ≤ b ≤ 20 เศษส่วนในข้อมูลเข้าอาจยังไม่เป็นอย่างต่ำ และอาจมากกว่าหนึ่งถ้วยก็ได้

ข้อมูลออก

ผลรวมเป็นเศษส่วนอย่างต่ำในรูป p/q หรือพิมพ์ p อย่างเดียวถ้า q เป็น 1

3
3/4
1/3
5/6
23/12
3
1/2
3/4
3/4
2
ดูคำใบ้

รับเศษส่วนด้วย scanf("%d/%d", ...) แบบตัวคั่นในหน้า 2.3 เก็บผลรวมไว้เป็น p/q เริ่มที่ 0/1 แล้วบวกทีละตัวด้วยสูตร p/q + a/b = (p × b + a × q)/(q × b) หลังบวกทุกครั้ง ให้หารทั้ง p และ q ด้วย gcd(p, q) ของหน้า 8.5 ถ้ารอทำอย่างต่ำตอนท้ายทีเดียว ส่วนจะเป็นผลคูณของตัวส่วนทั้ง 20 ตัว ซึ่งล้น long long ได้ ระหว่างทาง p × b และ q × b ก็เกิน int ได้ จึงต้องใช้ long long ทั้ง p q และพารามิเตอร์ของ gcd

ดูเฉลย
#include <stdio.h>

long long gcd(long long a, long long b)
{
    while (b != 0) {
        long long remainder = a % b;
        a = b;
        b = remainder;
    }
    return a;
}

int main()
{
    int n;
    scanf("%d", &n);
    long long top = 0;
    long long bottom = 1;
    for (int i = 0; i < n; i++) {
        int a, b;
        scanf("%d/%d", &a, &b);
        top = top * b + a * bottom;
        bottom = bottom * b;
        long long g = gcd(top, bottom);
        top /= g;
        bottom /= g;
    }
    if (bottom == 1) {
        printf("%lld\n", top);
    } else {
        printf("%lld/%lld\n", top, bottom);
    }
    return 0;
}

ข้อ 7 นับวันระหว่างสองวันที่

ระดับยาก เวลาไม่เกิน 1 วินาที

แอปนับวันของโรงเรียนต้องตอบคำถาม Q ข้อ แต่ละข้อถามว่า จากวันที่หนึ่งไปถึงอีกวันที่หนึ่ง ห่างกันกี่วัน เช่น จากวันที่ 28 กุมภาพันธ์ 2024 ถึงวันที่ 1 มีนาคม 2024 ห่างกัน 2 วัน เพราะปี 2024 มีวันที่ 29 กุมภาพันธ์คั่นอยู่ ถ้าเป็นวันเดียวกัน ห่างกัน 0 วัน

เดือน 4 6 9 11 มี 30 วัน เดือน 2 มี 29 วันในปีอธิกสุรทิน และ 28 วันในปีอื่น เดือนที่เหลือมี 31 วัน ปีอธิกสุรทินคือปีที่หารด้วย 4 ลงตัวแต่หารด้วย 100 ไม่ลงตัว หรือปีที่หารด้วย 400 ลงตัว ปีทุกปีในข้อนี้เป็นปีคริสต์ศักราช

ข้อมูลเข้า

บรรทัดแรกมีจำนวนเต็ม Q โดยที่ 1 ≤ Q ≤ 100000

อีก Q บรรทัดต่อมา บรรทัดละหนึ่งคำถาม มีจำนวนเต็มหกตัว D1 M1 Y1 D2 M2 Y2 คั่นด้วยช่องว่าง คือวันที่เริ่มและวันที่จบ ทั้งสองเป็นวันที่ที่มีอยู่จริง ปีอยู่ระหว่าง 1900 ถึง 2600 และวันที่จบไม่มาก่อนวันที่เริ่ม

ข้อมูลออก

Q บรรทัด บรรทัดที่ i เป็นจำนวนวันจากวันที่เริ่มถึงวันที่จบของคำถามที่ i

3
28 2 2024 1 3 2024
21 10 2026 21 10 2026
1 1 2026 1 1 2027
2
0
365
3
28 2 1900 1 3 1900
28 2 2000 1 3 2000
31 12 2025 1 1 2026
1
2
1
ดูคำใบ้

เดินทีละวันแบบข้อวันพรุ่งนี้ในบทที่ 3 ถูกต้อง แต่คำถามหนึ่งข้ออาจห่างกันถึงสองแสนกว่าวัน คูณกับแสนคำถามแล้วช้าเกินไป ให้เปลี่ยนวันที่ทุกวันเป็นเลขลำดับวันนับจากวันที่ 1 มกราคม 1900 แทน แล้วคำตอบคือเลขลำดับของวันจบลบเลขลำดับของวันเริ่ม แบ่งเป็นสามฟังก์ชัน is_leap(year) days_in_month(month, year) และ day_number(day, month, year) ที่บวกจำนวนวันของทุกปีก่อนหน้า ทุกเดือนก่อนหน้าในปีนั้น แล้วบวก day ทดสอบกับ 28 กุมภาพันธ์ถึง 1 มีนาคมของปี 1900 2000 และ 2024

ดูเฉลย
#include <stdio.h>

int is_leap(int year)
{
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

int days_in_month(int month, int year)
{
    if (month == 2) {
        return is_leap(year) ? 29 : 28;
    }
    if (month == 4 || month == 6 || month == 9 || month == 11) {
        return 30;
    }
    return 31;
}

int day_number(int day, int month, int year)
{
    int total = 0;
    for (int y = 1900; y < year; y++) {
        total += is_leap(y) ? 366 : 365;
    }
    for (int m = 1; m < month; m++) {
        total += days_in_month(m, year);
    }
    return total + day;
}

int main()
{
    int q;
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        int d1, m1, y1, d2, m2, y2;
        scanf("%d %d %d %d %d %d", &d1, &m1, &y1, &d2, &m2, &y2);
        printf("%d\n", day_number(d2, m2, y2) - day_number(d1, m1, y1));
    }
    return 0;
}

ข้อ 8 ป้ายไฟตัวเลข

ระดับยาก เวลาไม่เกิน 1 วินาที

ป้ายไฟหน้าห้องสมุดแสดงตัวเลขด้วยหลอดไฟ 7 ท่อน แต่ละหลักประกอบด้วยท่อนบน (a) ท่อนขวาบน (b) ท่อนขวาล่าง (c) ท่อนล่าง (d) ท่อนซ้ายล่าง (e) ท่อนซ้ายบน (f) และท่อนกลาง (g) ตัวเลขแต่ละตัวเปิดท่อนต่อไปนี้

เลขท่อนที่เปิดเลขท่อนที่เปิด
0a b c d e f5a c d f g
1b c6a c d e f g
2a b d e g7a b c
3a b c d g8a b c d e f g
4b c f g9a b c d f g

ป้ายปรับขนาดได้ด้วยค่า S ตัวเลขหนึ่งหลักกว้าง S + 2 คอลัมน์ สูง 2S + 3 แถว ช่องที่ไฟติดพิมพ์เป็น # ช่องที่ไฟดับพิมพ์เป็น . นับแถวจาก 1 ด้านบน และนับคอลัมน์จาก 1 ด้านซ้าย

  • ท่อน a อยู่แถวที่ 1 ท่อน g อยู่แถวที่ S + 2 ท่อน d อยู่แถวที่ 2S + 3 ทั้งสามท่อนกินคอลัมน์ที่ 2 ถึง S + 1
  • ท่อน f กับ b อยู่แถวที่ 2 ถึง S + 1 ท่อน e กับ c อยู่แถวที่ S + 3 ถึง 2S + 2 ท่อน f กับ e อยู่คอลัมน์ที่ 1 ท่อน b กับ c อยู่คอลัมน์ที่ S + 2
  • มุมทั้งสี่และช่องอื่นที่ไม่อยู่ในท่อนใดเป็น . เสมอ

ตัวเลขหลายหลักวางเรียงจากซ้ายไปขวาตามลำดับ ระหว่างสองหลักที่ติดกันคั่นด้วยคอลัมน์ของ . หนึ่งคอลัมน์ ดูรูปจากตัวอย่าง

ข้อมูลเข้า

บรรทัดเดียว มีจำนวนเต็ม S และตัวเลข D คั่นด้วยช่องว่าง โดยที่ 1 ≤ S ≤ 10 และ D เป็นตัวเลข 0 ถึง 9 เรียงติดกัน 1 ถึง 20 หลัก D อาจขึ้นต้นด้วย 0 และต้องแสดง 0 นั้นด้วย

ข้อมูลออก

รูปป้ายไฟ 2S + 3 บรรทัด

1 0123456789
.#.......#...#.......#...#...#...#...#.
#.#...#...#...#.#.#.#...#.....#.#.#.#.#
.........#...#...#...#...#.......#...#.
#.#...#.#.....#...#...#.#.#...#.#.#...#
.#.......#...#.......#...#.......#...#.
2 2026
.##...##...##...##.
...#.#..#....#.#...
...#.#..#....#.#...
.##........##...##.
#....#..#.#....#..#
#....#..#.#....#..#
.##...##...##...##.
ดูคำใบ้

รับ D เป็นสตริงด้วย %s เพราะอาจขึ้นต้นด้วย 0 และยาวเกิน long long เก็บตารางท่อนไว้เป็นอาเรย์ของสตริง เช่น "abcdef" สำหรับเลข 0 แล้วเขียน int is_on(int digit, char segment) ที่ไล่หาตัวอักษรในสตริงนั้น ป้ายมีแถวแค่สองแบบ แถวท่อนนอน (a g d) กับแถวท่อนตั้ง (f b หรือ e c) จึงเขียนสองฟังก์ชัน print_horizontal(char segment) และ print_vertical(char left, char right) ที่พิมพ์ทั้งแถวครบทุกหลัก แล้ว main เรียกตามลำดับแถว ระวังอย่าพิมพ์ . คั่นหลังหลักสุดท้าย

ดูเฉลย
#include <stdio.h>

char segments[10][8] = {"abcdef", "bc", "abdeg", "abcdg", "bcfg",
                        "acdfg", "acdefg", "abc", "abcdefg", "abcdfg"};
char digits[25];
int size;

int is_on(int digit, char segment)
{
    for (int i = 0; segments[digit][i] != '\0'; i++) {
        if (segments[digit][i] == segment) {
            return 1;
        }
    }
    return 0;
}

void print_repeat(char symbol, int count)
{
    for (int i = 0; i < count; i++) {
        printf("%c", symbol);
    }
}

void print_horizontal(char segment)
{
    for (int i = 0; digits[i] != '\0'; i++) {
        if (i > 0) {
            printf(".");
        }
        printf(".");
        print_repeat(is_on(digits[i] - '0', segment) ? '#' : '.', size);
        printf(".");
    }
    printf("\n");
}

void print_vertical(char left, char right)
{
    for (int i = 0; digits[i] != '\0'; i++) {
        int digit = digits[i] - '0';
        if (i > 0) {
            printf(".");
        }
        printf("%c", is_on(digit, left) ? '#' : '.');
        print_repeat('.', size);
        printf("%c", is_on(digit, right) ? '#' : '.');
    }
    printf("\n");
}

int main()
{
    scanf("%d %s", &size, digits);
    print_horizontal('a');
    for (int r = 0; r < size; r++) {
        print_vertical('f', 'b');
    }
    print_horizontal('g');
    for (int r = 0; r < size; r++) {
        print_vertical('e', 'c');
    }
    print_horizontal('d');
    return 0;
}