P1202 [USACO1.1] 黑色星期五Friday the Thirteenth
题目描述
13 13 13 号又是一个星期五,那么 13 13 13 号在星期五比在其他日子少吗?
为了回答这个问题,写一个程序,要求计算每个月的十三号落在周一到周日的次数。给出 n n n 年的一个周期,要求计算 1900 1900 1900 年 1 1 1 月 1 1 1 日至 1900 + n − 1 1900+n-1 1900+n−1 年 12 12 12 月 31 31 31 日中十三号落在周一到周日的次数。
这里有一些你要知道的:
- 1900 1900 1900 年 1 1 1 月 1 1 1 日是星期一。
- 4 , 6 , 11 4,6,11 4,6,11 和 9 9 9 月有 30 30 30 天,其他月份除了 2 2 2 月都有 31 31 31 天,闰年 2 2 2 月有 29 29 29 天,平年 2 2 2 月有 28 28 28 天。
- 年份可以被 4 4 4 整除的为闰年( 1992 = 4 × 498 1992=4\times 498 1992=4×498 所以 1992 1992 1992 年是闰年,但是 1990 1990 1990 年不是闰年)。
- 以上规则不适合于世纪年。可以被 400 400 400 整除的世纪年为闰年,否则为平年。所以, 1700 , 1800 , 1900 , 2100 1700,1800,1900,2100 1700,1800,1900,2100 年是平年,而 2000 2000 2000 年是闰年。
输入格式
一个正整数 n n n。
输出格式
依次输出周六、日、一、二、三、四、五在 13 13 13 日出现的次数。
输入输出样例 #1
输入 #1
20
输出 #1
36 33 34 33 35 35 34
说明/提示
【数据范围】:对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 400 1\le n \le 400 1≤n≤400。
USACO Training Section 1.1
提交链接
Friday the Thirteenth
思路分析
✅ 总体思路
本题要求统计从 1900 1900 1900 年 1 1 1 月 1 1 1 日开始,连续 n n n 年 中,每个月的 13 13 13 号是星期几的次数,并按照指定顺序输出每个星期几出现的次数。
采用模拟法,从 1900 1900 1900 年 1 1 1 月 1 1 1 日开始,逐月推进,通过取模计算每月 13 13 13 号是星期几,并用数组统计每个星期几出现的频率。
🔍 逐步分析
1️⃣ 定义变量与判断闰年函数
int num[7];
-
n u m [ i ] num[i] num[i] 表示星期 i i i 上出现
13号
的次数 -
星期编号:
0=周日
,1=周一
,…,6=周六
bool is_year(int x)
{return (x % 4 == 0 && x % 100 != 0) || x % 400 == 0;
}
-
判断年份 x x x 是否是闰年
-
遵循闰年规则:能被 4 4 4 整除但不能被 100 100 100 整除,或能被 400 400 400 整除
2️⃣ 每月天数判断函数 solve
int solve(int x , int y)
-
返回 x x x 年 y y y 月的天数
-
2 2 2月特殊处理,调用
is_year()
判断是否是闰年 -
4 4 4、 6 6 6、 9 9 9、 11 11 11 月为 30 30 30 天,其余为 31 31 31 天
3️⃣ 主函数逻辑
int day = 1; // 1900年1月1日是周一
-
day
表示当前月份的 1 1 1 号是星期几; -
使用取模来推进计算,
(day + 12) % 7
表示本月 13 13 13 号是星期几
4️⃣ 双层循环:年份 & 月份推进
for (int i = 1900; i <= 1900 + n - 1; i++)
{for (int j = 1; j <= 12; j++) {int k = (day + 12) % 7;num[k]++;day = (day + solve(i , j)) % 7;}
}
-
i i i 从 1900 1900 1900 年开始循环 n n n 年
-
j j j 从 1 1 1 月到 12 12 12 月
-
(day + 12) % 7
:当前月份 13 13 13 号是星期几 -
num[k]++
:统计这个星期几出现了一个 “13号” -
day = (day + 天数) % 7
:推算下个月 1 1 1 号是星期几
5️⃣ 输出结果
cout << num[6] << " " << num[0];
for(int i = 1; i <= 5; i++)cout << " " << num[i];
-
题目要求输出顺序为:周六 周日 周一 周二 周三 周四 周五;
-
因为
0 = 周日, 1 = 周一, ..., 6 = 周六
,所以输出顺序就是:
num[6], num[0], num[1], ..., num[5]
完整代码:
#include <bits/stdc++.h>
using namespace std;int num[7];
bool is_year(int x)
{if (x % 4 == 0 && x % 100 != 0 || x % 400 == 0)return true;return false;
}int solve(int x , int y)
{if(y == 2)return is_year(x) ? 29 : 28;else if(y == 4 || y == 6 || y == 9 || y == 11)return 30;elsereturn 31;
}
int main()
{int n;cin >> n;int day = 1; //每月的1号为周几 初始为周一for (int i = 1900; i <= 1900 + n - 1; i++){for (int j = 1; j <= 12; j++){//每一个月的13号 判断周几?int k = (day + 12) % 7;num[k]++;day = (day + solve(i , j)) % 7; //下月1号星期几}}cout << num[6] << " " << num[0];for(int i = 1; i <= 5; i++)cout << " " << num[i];return 0;
}