USACO Section 1.1 Friday the Thirteenth 解题报告
题目
题目描述
黑色星期五是否真的是一件不同寻常的事情?按理来说每个月的13号可能是星期一,或者是星期二...或者是星期天,但是黑色星期五的存在让我们不禁开始猜想,难道每个月的13号刚好是星期五的频率很少吗?现在我们需要对这个事件进行研究一下。
黑色星期五源于西方的宗教信仰:耶稣基督死在星期五,而13是不吉利的数字,两者的结合令人相信当天会发生不幸的事情。现在中国也有许多信仰基督教的教徒,自然,黑色星期五在中国传开了。两者的结合令人相信当天会发生不幸的事情。星期五和数字13都代表着坏运气,两个不幸的个体最后结合成超级不幸的一天。所以,不管哪个月的十三日又恰逢星期五就叫“黑色星期五”。
我们从1900年1月1日开始,一直到N年之后,也就是直到(1900+N-1)年的12月31日。我们需要统计在这段时间当中,每个月的13日是星期几,最终输出星期一到星期天在这N年的每个月13日中出现了多少次。要求按照星期六、星期天...星期五的次序输出。
数据范围
0 <= N <= 400
- 1900年1月1日是星期一
- 注意平年与闰年的差异
样例输入
20
样例输出
36 33 34 33 35 35 34
解题思路
我们通过枚举1900年到(1900+N-1)年的每个月,然后计算这个月的13日与1900年1月1日相差多少天,这样我们就能算出这个月的13日是星期几,然后记录下来。
在编写代码的时候,容易犯的错误有:平年闰年的判断,最终的结果顺序输出错误,下意识的计算成每一年的每月13日与该年的1月1日的差(我最开始就犯了这个错误...)
解题代码
/*
ID: yinzong2
PROG: friday
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int d[7];
int daysOfMonth[13][2] = {{0,0}, {31,31}, {28,29}, {31,31}, {30,30}, {31,31}, {30,30},
{31,31}, {31,31}, {30,30}, {31,31}, {30,30}, {31,31}};
int n;
int isLeap(int y) {
if((y%400 == 0) || ((y%4 == 0)&&(y%100 != 0))) {
return 1;
}
return 0;
}
void cal(int begin, int end) {
int leap = 0;
int sum = 0;
for(int i = begin; i < end; i++) {
leap = isLeap(i);
for(int j = 1; j <= 12; j++) {
d[ (sum+13)%7 ]++;
//关键是在这个地方避免我之前出现的错误
sum += daysOfMonth[j][leap];
}
}
}
int main() {
#ifdef MARK
freopen("friday.in", "r", stdin);
freopen("friday.out", "w", stdout);
#endif
while(~scanf("%d", &n)) {
memset(d, 0, sizeof(d));
int beginYear = 1900;
int endYear = 1900+n;
cal(beginYear, endYear);
for(int i = 6, j = 0; j < 7; j++, i = (i+1)%7) {
if(j) printf(" ");
printf("%d", d[i]);
}
printf("\n");
}
return 0;
}