题目描述

请你计算出第X年Y月Z日是第X年的第几天。其中,1月1日是第一天,1月2日是第二天,以此类推。

计算时请注意闰年的影响。对于非整百年,年数能整除4是闰年,否则不是闰年;对于整百年,年数能整除400是闰年,否则不是闰年。如1900年和1901年不是闰年,而2000年和2004年是闰年。

题目链接

思路

这是个典型的涉及闰年的日期问题, 要求解某一年是第几天.思路很直接,从月份入手,先计算前$ Y-1$个月一共有多少天,然后在加上这个月中这一天之前有多少天,就可以得到结果.

输入输出处理

在所有 OJ 中,输入输出都是绕不过的坎,很多时候会因为输出处理不好而导致莫名其妙的 WA, 又有很多时候可以从输入格式中获得解题的灵感.

回到本题,输入格式为X:Y:Z的形式, X,Y,Z 都是整数, 以冒号隔开.这不由得让我们想到了可以利用 scanf 的格式字段做”手脚”, 直接将 X, Y, Z 读入到整形变量当中进行后续的处理.所以有了以下代码来处理日期的输入.

1
2
int X,Y,Z;
scanf("%d:%d:%d",&X,&Y,&Z);

输出方面,只需要输出天数,是一个整形变量,没有什么特别的技巧.

注意事项

这部分描述题目中的”边沿”情况, 如果忽略这些情况,就会导致 WA

闰年的处理

题目中也给出了提示.在代码中可以利用宏来判断闰年.

1
#define ISYEAP(x) ((x%100!=0)&&(x%4==0))||(x%400==0)?1:0

使用宏的时候一定要注意, 编译器在编译的时候会将宏展开之后插到每一个调用宏的地方,为了避免由于运算符优先级问题带来奇奇怪怪的 bug, 建议前后用括号括起来,像这样( ISYEA(X))

一月份

1月份的时候,天数即为当日的日期,直接输出 Z 字段即可.

二月份

这也是个容易踩坑的地方,大家都知道闰年要算2月29天,但有时太匆忙的时候,会糊里糊涂把闰年1月2月的日期也会莫名其妙的加上了”1天”,导致 WA. 因此要单独处理.也可以通过构造合理的if 语句和一月份的情况一起处理.

对每个月的日子进行预处理

在程序开始之前可以定义一个数组储存每个月的天数, 计算日子时直接根据下标找到天数相加即可,可以减少代码量和运行时间.

预处理的时候要注意, c 语言的数组下标从0开始, 而月份是从1月开始,所以可以构造一个13个元素的数组并且让第一个元素值为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
#include <cstdio>
#define ISYEAP(x) ((x%100!=0)&&(x%4==0))||(x%400==0)?1:0
int daysOfMonth[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int main(){
int T;
scanf("%d",&T);
while(T--){
int yy,mm,dd;
int days=0;
scanf("%d:%d:%d",&yy,&mm,&dd);
if(mm==1){
days = dd;//special situation
}else{
for(int i = 1;i<mm;i++){
days+=daysOfMonth[i];
}
days+=dd;
if(ISYEAP(yy)){
if(mm>2){
days++;
}
}
}
printf("%d\n",days);
}
}