昨天参加了传智杯的练习赛,里面有一题卡了我很久,今天整理一下记录到博客。
题目描述
输入格式
按照 日月年 的格式输入数据,其中日是 1 到 31 之间的整数,月是三个大写字母,年是 1 到 9999 之间的整数。保证这个日期是合法且存在的。
月份的大写字母:
1月:JAN
2月:FEB
3月:MAR
4月:APR
5月:MAY
6月:JUN
7月:JUL
8月:AUG
9月:SEP
10月:OCT
11月:NOV
12月:DEC
输出格式
输出一个整数表示答案
样例
输入 | 输出 | |
---|---|---|
1 | 1JAN1 | 0 |
2 | 4OCT1582 | 577736 |
3 | 15OCT1582 | 577737 |
4 | 21NOV2020 | 737751 |
思路
这道题我分成了两部分,一部分处理年份在1582及之前的,另一部分处理年份大于1582的。
变量定义
首先是接受输入的三个变量
int year, month, day;
string strMonth = "???";
然后是记录答案的变量
int ans;
最后定义一个数组来记录月份的天数
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
接受输入
cin >> day;
strMonth[0] = cin.get(), strMonth[1] = cin.get(), strMonth[2] = cin.get();
cin >> year;
month = toIntMonth(strMonth);
因为输入的月份是英文的不便于计算,所以设计函数(toIntMonth)将其转化为整型月份
int toIntMonth(string m) {
if (m == "JAN") return 1;
else if (m == "FEB") return 2;
else if (m == "MAR") return 3;
else if (m == "APR") return 4;
else if (m == "MAY") return 5;
else if (m == "JUN") return 6;
else if (m == "JUL") return 7;
else if (m == "AUG") return 8;
else if (m == "SEP") return 9;
else if (m == "OCT") return 10;
else if (m == "NOV") return 11;
else if (m == "DEC") return 12;
return 0;
}
第一部分
这一部分处理的是1582及之前年份。
计算步骤如下:
- 将年份-1进行计算经过的闰年数
- ans赋值为(年份-1)*365+闰年数
- ans += 这一年的月份 - 1的总天数
- ans += day
代码如下
if (year <= 1582) {
//之前年份的日数
year--;
ans = year * 365 + getLeepYearCount1(year);
year++;
//获取之前月份的日数 + 当前月份的日数
ans += getDayByMonth(month - 2, isLeepYear1(year)) + day;
//1582年份的特殊判断
if (year == 1582) {
//在[1582.10.5, 1582.10.14]之间的特殊天数(不记录)
if (month == 10 && day > 4 && day < 15) ans -= day - 4;
//在1582.10.15日及之后该年剩下的日子-10天,因为10月的5-14日不存在
else if ((month == 10 && day >= 15) || (month > 10)) ans -= 10;
}
}
其中getLeepYearCount1的功能是计算1到当前年份(1582之前)的闰年数量
int getLeepYearCount1(int y) {
return y / 4;
}
isLeepYear1是用来判断这一年(1582年之前)是否为闰年
bool isLeepYear1(int y) {
return y % 4 == 0;
}
getDayByMonth是获取这一年中经过的天数(r代表是否为闰年)
int getDayByMonth(int mon, bool r) {
if (mon < 0) return 0;
if (r) months[1]++;
for (int i = 1; i <= mon; i++) {
months[i] += months[i - 1];
}
return months[mon];
}
第二部分
这一部分处理的是1582之后的年份。
计算步骤如下和第一部分差不多:
else {
//之前年份的日数
year--;
ans = year * 365 + getLeepYearCount2(year);
year++;
//获取之前月份的日数 + 当前月份的日数 - 10(十天是因为1582年10月的5-14日不存在)
ans += getDayByMonth(month - 2, isLeepYear2(year)) + day - 10;
}
isLeepYear2是用来判断这一年(1582年之后)是否为闰年
bool isLeepYear2(int y) {
return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
getLeepYearCount2和getLeepYearCount1差不多,只不过在1582年之后采用新的计算方式
int getLeepYearCount2(int y) {
int c = 0;
for (int i = 1582; i <= y; i++) {
if (isLeepYear2(i)) {
c++;
}
}
//395是1582年之前的闰年数
return c + 395;
}
输出
cout << ans - 1;
这里减一是因为距离公元1.1.1的天数不包括今天的
代码实现
#include <bits/stdc++.h>
using namespace std;
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int toIntMonth(string m) {
if (m == "JAN") return 1;
else if (m == "FEB") return 2;
else if (m == "MAR") return 3;
else if (m == "APR") return 4;
else if (m == "MAY") return 5;
else if (m == "JUN") return 6;
else if (m == "JUL") return 7;
else if (m == "AUG") return 8;
else if (m == "SEP") return 9;
else if (m == "OCT") return 10;
else if (m == "NOV") return 11;
else if (m == "DEC") return 12;
return 0;
}
int getDayByMonth(int mon, bool r) {
if (mon < 0) return 0;
if (r) months[1]++;
for (int i = 1; i <= mon; i++) {
months[i] += months[i - 1];
}
return months[mon];
}
bool isLeepYear1(int y) {
return y % 4 == 0;
}
int getLeepYearCount1(int y) {
return y / 4;
}
bool isLeepYear2(int y) {
return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int getLeepYearCount2(int y) {
int c = 0;
for (int i = 1582; i <= y; i++) {
if (isLeepYear2(i)) {
c++;
}
}
//395是1582年之前的闰年数
return c + 395;
}
int main() {
int year, month, day;
string strMonth = "???";
int ans;
cin >> day;
strMonth[0] = cin.get(), strMonth[1] = cin.get(), strMonth[2] = cin.get();
cin >> year;
month = toIntMonth(strMonth);
if (year <= 1582) {
//之前年份的日数
year--;
ans = year * 365 + getLeepYearCount1(year);
year++;
//获取之前月份的日数 + 当前月份的日数
ans += getDayByMonth(month - 2, isLeepYear1(year)) + day;
//1582年份的特殊判断
if (year == 1582) {
//在[1582.10.5, 1582.10.14]之间的特殊天数(不记录)
if (month == 10 && day > 4 && day < 15) ans -= day - 4;
//在1582.10.15日及之后该年剩下的日子-10天,因为10月的5-14日不存在
else if ((month == 10 && day >= 15) || (month > 10)) ans -= 10;
}
} else {
//之前年份的日数
year--;
ans = year * 365 + getLeepYearCount2(year);
year++;
//获取之前月份的日数 + 当前月份的日数 - 10(十天是因为1582年10月的5-14日不存在)
ans += getDayByMonth(month - 2, isLeepYear2(year)) + day - 10;
}
cout << ans - 1;
return 0;
}