Content
输入一个日期,包括三个整数\(y,m,d\),即为这一天是\(y\)年\(m\)月\(d\)日,求出这一天距离\(2014\)年\(5\)月\(17\)日多少天。
数据范围:\(1\leqslant y\leqslant2014,1\leqslant m\leqslant12,1\leqslant d\leqslant31\)。
Solution
和P5407的方法有些类似,我的意思是说,核心代码部分,也就是推日期。
P5407这道题目我在去年也写过题解,提到了暴力推日期的代码实现方法,现在我再重新理一遍它的过程:
- 一开始,设定起始日期和目标日期。
注意,这里和P5407的不同点是,P5407一定是顺向推日期的(一年的元旦比母亲节还晚就不科学了),但是这一题中,输入的日期就可能比2014年5月17日早(比如2014年12月31日),所以,你可以像我后面讲的方法一样,逆向推日期(其实也不难),要么也可以将起始日期的三个元素和目标日期的三个元素(三个元素无需多提)逐一对应调换,然后再顺向推日期亦可。
- 然后判断,如果起始日期比目标日期晚,设有个变量\(flag\)初始值为\(1\),用来判断上述条件,此时\(flag\)变成\(-1\)。比较方法跟\(\texttt{sort}\)中多关键字的比较函数的写法有些类似。否则\(flag\)保持为\(1\)不变。
开始愉快地推日期。(注意先后顺序不能调换!)
-
先判断是否和目标日期相等,如果相等直接结束推日期。
-
如果\(flag\)为\(-1\),每次天数减\(1\)。然后判断如果天数\(<1\),那么月数减\(1\),天数变为这个月的最大天数。再判断此时如果月份数也\(<1\),那么年数也减\(1\),月数和天数分别变成\(12\)和\(31\)。
-
否则,如果\(flag\)为\(1\),每次天数加\(1\)。然后判断如果天数\(>\)当前所在月的最大天数,那么月数加\(1\),天数归\(1\),再判断此时如果月份数\(>12\),那么年数也加\(1\),月数和天数都归1。
在推日期的过程中,引进一个\(cnt\)变量记录天数,每次操作过后\(cnt\)加\(1\),推完日期之后\(cnt\)即为本题的答案,输出(不要忘了输出完后面换行!这是AT题库最致命的一个坑!)。
另外一种,就是调换日期再顺着推的方法,请读者自己思考,本题解不做过多解释。
Code
#include <cstdio>
#include <algorithm>
using namespace std;
int y, m, d, yy = 2014, mm = 5, dd = 17, flag = 1, cnt;
int ddd[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline int judge(int x) {
if(!(x % 100)) {
if(x % 400) return 0;
return 1;
}
if(x % 4) return 0;
return 1;
}
int main() {
scanf("%d%d%d", &y, &m, &d);
if(y != 2014 && y > 2014) flag = -1;
else if(m != 5 && m > 5) flag = -1;
else if(d != 17 && d > 17) flag = -1;
if(flag == -1) swap(y, yy), swap(m, mm), swap(d, dd);
// printf("%d %d %d %d %d %d", y, m, d, yy, mm, dd);
while(1) {
// printf("Today is %d.%d.%d\n", y, m, d);
if(d == dd && m == mm && y == yy) break;
cnt++;
if(flag == -1) {
d--;
if(d < 1) {m--; d = ddd[m] + (judge(y) && m == 2 ? 1 : 0);}
if(m < 1) {y--; m = 12; d = 31;}
} else {
d++;
if(d > ddd[m] + (judge(y) && m == 2 ? 1 : 0)) {m++; d = 1;}
if(m > 12) {y++; m = 1;}
}
}
printf("%d\n", cnt);
return 0;
}