【GESP】C++三级真题 luogu-B4414 [GESP202509 三级] 日历制作
GESP C++ 2025年9月三级真题,一维数组考点,难度★★☆☆☆。
luogu-B4414 [GESP202509 三级] 日历制作
题目要求
题目描述
小 A 想制作 $2025$ 年每个月的日历。他希望你能编写一个程序,按照格式输出给定月份的日历。
具体来说,第一行需要输出 MON TUE WED THU FRI SAT SUN,分别表示星期一到星期日。接下来若干行中依次输出这个月所包含的日期,日期的个位需要和对应星期几的缩写最后一个字母对齐。例如,$2025$ 年 $9$ 月 $1$ 日是星期一,在输出九月的日历时,$1$ 号的个位 $1$ 就需要与星期一 MON 的最后一个字母 N 对齐。九月的日历输出效果如下:
1 2 3 4 5 6 MON TUE WED THU FRI SAT SUN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30你能帮助小 A 完成日历的制作吗?
输入格式
一行,一个正整数 $m$,表示需要按照格式输出 $2025$ 年 $m$ 月的日历。
输出格式
输出包含若干行,表示 $2025$ 年 $m$ 月的日历。
输入输出样例 #1
输入 #1
1
9
输出 #1
1
2
3
4
5
6
MON TUE WED THU FRI SAT SUN
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
输入输出样例 #2
输入 #2
1
6
输出 #2
1
2
3
4
5
6
7
MON TUE WED THU FRI SAT SUN
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
说明/提示
对于所有测试点,保证 $1 \leq m \leq 12$。
题目分析
确定 2025 年任意月份 1 号是星期几
以 2025-09-01(星期一)为基准,向前或向后累加整月天数,再对 7 取模即可得到目标月首日的星期偏移(1=MON…7=SUN)。- 排版日历
- 第一行固定输出星期标题。
- 根据“首日是星期几”先在对应位置补空格,使 1 号的个位与星期缩写的末字符对齐。
- 之后顺序输出该月所有日期,每 7 个换行。
- 实现策略
- 方法一(硬编码):把 12 个月的首日偏移和天数全部手算后写进
switch
,考场“秒过”。 - 方法二(计算法):用数组预存每月天数,以 9 月为基准向前/向后累加天数,动态算出偏移,通用且易改年份。
- 方法一(硬编码):把 12 个月的首日偏移和天数全部手算后写进
两种思路均只需 $O(1)$ 预处理、$O(D)$ 输出($D$ 为当月天数),轻松通过 GESP 三级数据范围。
示例代码
方法一 应试”白给“法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <cstdio>
#include <iostream>
int main() {
int m;
std::cin >> m; // 读入需要输出的月份
std::cout << "MON TUE WED THU FRI SAT SUN\n"; // 打印星期标题行
// 针对2025年各月1日对应的星期偏移(已硬编码)
// 通过 switch 分支直接控制该月日历的排版
switch (m) {
case 1:
// 1月:1号为星期三,前面空2格
for (int i = 1; i <= 33; i++) { // 33 = 31天 + 2个空位
if (i <= 2) {
printf(" "); // 占位4空格(含后续分隔)
} else {
printf("% 3d ", i - 2); // 右对齐3位数字 + 1空格
}
if (i % 7 == 0) { // 每7列换行
std::cout << "\n";
}
}
break;
case 2:
// 2月:1号为星期六,前面空5格
for (int i = 1; i <= 33; i++) { // 28天 + 5空位
if (i <= 5) {
printf(" ");
} else {
printf("% 3d ", i - 5);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 3:
// 3月:1号为星期六,前面空5格
for (int i = 1; i <= 36; i++) { // 31天 + 5空位
if (i <= 5) {
printf(" ");
} else {
printf("% 3d ", i - 5);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 4:
// 4月:1号为星期二,前面空1格
for (int i = 1; i <= 31; i++) { // 30天 + 1空位
if (i <= 1) {
printf(" ");
} else {
printf("% 3d ", i - 1);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 5:
// 5月:1号为星期四,前面空3格
for (int i = 1; i <= 34; i++) { // 31天 + 3空位
if (i <= 3) {
printf(" ");
} else {
printf("% 3d ", i - 3);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 6:
// 6月:1号为星期日,前面空6格
for (int i = 1; i <= 36; i++) { // 30天 + 6空位
if (i <= 6) {
printf(" ");
} else {
printf("% 3d ", i - 6);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 7:
// 7月:1号为星期二,前面空1格
for (int i = 1; i <= 32; i++) { // 31天 + 1空位
if (i <= 1) {
printf(" ");
} else {
printf("% 3d ", i - 1);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 8:
// 8月:1号为星期五,前面空4格
for (int i = 1; i <= 35; i++) { // 31天 + 4空位
if (i <= 4) {
printf(" ");
} else {
printf("% 3d ", i - 4);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 9:
// 9月:1号为星期一,无偏移
for (int i = 1; i <= 30; i++) { // 30天
printf("% 3d ", i);
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 10:
// 10月:1号为星期三,前面空2格
for (int i = 1; i <= 33; i++) { // 31天 + 2空位
if (i <= 2) {
printf(" ");
} else {
printf("% 3d ", i - 2);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 11:
// 11月:1号为星期六,前面空5格
for (int i = 1; i <= 35; i++) { // 30天 + 5空位
if (i <= 5) {
printf(" ");
} else {
printf("% 3d ", i - 5);
}
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
case 12:
// 12月:1号为星期一,无偏移
for (int i = 1; i <= 31; i++) { // 31天
printf("% 3d ", i);
if (i % 7 == 0) {
std::cout << "\n";
}
}
break;
default:
break;
}
return 0;
}
方法二 正常计算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cstdio>
#include <iostream>
// 2025年各月天数,0号元素占位,1~12月分别对应实际天数
int month_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main() {
int m;
std::cin >> m; // 读入需要输出的月份
std::cout << "MON TUE WED THU FRI SAT SUN\n"; // 打印星期标题行
int start_day = 1; // 2025年9月1日为星期一,作为基准
int total_days = 0; // 累计从基准月到目标月之间的总天数
if (m == 9) {
// 目标月就是9月,无需累加,直接已知start_day=1
start_day = 1;
} else if (m < 9) {
// 目标月在9月之前,从m月累加到8月
for (int i = m; i < 9; i++) {
total_days += month_days[i];
}
// 计算相对于基准的星期偏移:往前推total_days天
// 往前推 total_days 天,计算新的星期偏移
// 7 代表星期日,公式保证结果落在 1~7 之间
start_day = 7 - (total_days - 1) % 7;
} else {
// 目标月在9月之后,从9月累加到m-1月
for (int i = 9; i < m; i++) {
total_days += month_days[i];
}
// 往后推total_days天
start_day += total_days % 7;
}
// 打印该月日历:循环总格数 = 月初偏移 + 该月天数
for (int i = 1; i <= month_days[m] + start_day - 1; i++) {
if (i < start_day) {
std::cout << " " << " "; // 月初前的空白天
} else {
printf("% 3d ", i - start_day + 1); // 右对齐输出日期
}
if (i % 7 == 0) {
std::cout << "\n"; // 每7列换行
}
}
return 0;
}
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP 学习专题站:GESP WIKI
“luogu-”系列题目可在洛谷题库进行在线评测。
“bcqm-”系列题目可在编程启蒙题库进行在线评测。
欢迎加入:Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答
欢迎加入:C++ GESP/CSP认证学习QQ频道,考试资源总结汇总
欢迎加入:C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助