202509-日历制作(luogu-B4414)
GESP C++ 2025年9月三级真题,一维数组考点,难度★★☆☆☆。
luogu-B4414 [GESP202509 三级] 日历制作
题目要求
题目描述
小 A 想制作 年每个月的日历。他希望你能编写一个程序,按照格式输出给定月份的日历。
具体来说,第一行需要输出 MON TUE WED THU FRI SAT SUN,分别表示星期一到星期日。接下来若干行中依次输出这个月所包含的日期,日期的个位需要和对应星期几的缩写最后一个字母对齐。例如, 年 月 日是星期一,在输出九月的日历时, 号的个位 就需要与星期一 MON 的最后一个字母 N 对齐。九月的日历输出效果如下:
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 完成日历的制作吗?
输入格式
一行,一个正整数 ,表示需要按照格式输出 年 月的日历。
输出格式
输出包含若干行,表示 年 月的日历。
输入输出样例 #1
输入 #1
9
输出 #1
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
6
输出 #2
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
说明/提示
对于所有测试点,保证 。
题目分析
确定 2025 年任意月份 1 号是星期几
以 2025-09-01(星期一)为基准,向前或向后累加整月天数,再对 7 取模即可得到目标月首日的星期偏移(1=MON…7=SUN)。排版日历
- 第一行固定输出星期标题。
- 根据“首日是星期几”先在对应位置补空格,使 1 号的个位与星期缩写的末字符对齐。
- 之后顺序输出该月所有日期,每 7 个换行。
实现策略
- 方法一(硬编码):把 12 个月的首日偏移和天数全部手算后写进
switch
,考场“秒过”。 - 方法二(计算法):用数组预存每月天数,以 9 月为基准向前/向后累加天数,动态算出偏移,通用且易改年份。
- 方法一(硬编码):把 12 个月的首日偏移和天数全部手算后写进
两种思路均只需 预处理、 输出( 为当月天数),轻松通过 GESP 三级数据范围。
示例代码
方法一 应试”白给“法
#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;
}
方法二 正常计算法
#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;
}
本文由coderli.com原创,按照CC BY-NC-SA 4.0 进行授权
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
“luogu-”系列题目可在 洛谷题库 在线评测。
“bcqm-”系列题目可在 编程启蒙题库 在线评测。
GESP/CSP 认证学习微信公众号

最后更新于