日期问题在蓝桥杯中出现很多次,总是变着花样去考,但是归根到底就是几个模板,本文给出一些代码模板和相关题目。
常用的代码模板:
一、天数定义
```
int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
将months
数组定义为全局变量
二、闰年判断
代码模板
int is_leap(int year) {
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
return 1;
}
return 0;
}
有人可能会问这里为什么不用bool
类型函数,其实bool
类型和int
类型都可以,我这里设为int
类型是为了后续更加方便
三、获取天数
代码模板
int getdays(int year, int month) {
if (month == 2) {
return months[2] + is_leap(year);
}
return months[month];
}
这里就调用了上述is_leap
函数,如果为闰年直接就加1,否则加0,判断起来更为简单
日期问题的相关题目:
1.蓝桥杯 2017 省 B 日期问题
题目描述
小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日
的,有采用月/日/年
的,还有采用日/月/年
的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如 02/03/04
,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式
一个日期,格式是 AA/BB/CC
(0 <= A, B, C <= 9)
输出格式
输出若干个不相同的日期,每个日期一行,格式是 yyyy-MM-dd
。多个日期按从早到晚排列。
样例 #1
样例输入 #1
02/03/04
样例输出 #1
2002-03-04
2004-02-03
2004-03-02
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int a, b, c;
vector<pair<int, pair<int, int>>> res;
const int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leap(int x) {
if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0)) {
return 1;
}
return 0;
}
int getdays(int y, int m) {
if (m == 2) {
return months[2] + is_leap(y);
}
return months[m];
}
bool judge_y(int y) {
if (y > 60) {
return true;
}
return false;
}
bool judge_m(int m) {
if (m <= 0 || m >= 13) {
return false;
}
return true;
}
bool judge_d(int y, int m, int d) {
if (d > 0 && d <= getdays(y, m)) {
return true;
}
return false;
}
int main() {
scanf("%d/%d/%d", &a, &b, &c);
if (judge_y(a)) {
if (judge_m(b) && judge_d(1900 + a, b, c)) {
res.push_back({1900 + a, {b, c}});
}
} else {
if (judge_m(b) && judge_d(2000 + a, b, c)) {
res.push_back({2000 + a, {b, c}});
}
}
if (c > 60) {
if (a != b) {
if (judge_m(a) && judge_d(1900 + c, a, b)) {
res.push_back({1900 + c, {a, b}});
}
if (judge_m(b) && judge_d(1900 + c, b, a)) {
res.push_back({1900 + c, {b, a}});
}
} else {
if (judge_m(b) && judge_d(1900 + c, b, a)) {
res.push_back({1900 + c, {b, a}});
}
}
} else {
if (a != b) {
if (judge_m(a) && judge_d(2000 + c, a, b)) {
res.push_back({2000 + c, {a, b}});
}
if (judge_m(b) && judge_d(2000 + c, b, a)) {
res.push_back({2000 + c, {b, a}});
}
} else {
if (judge_m(b) && judge_d(2000 + c, b, a)) {
res.push_back({2000 + c, {b, a}});
}
}
}
sort(res.begin(), res.end());
for (int i = 0; i < res.size(); i++) {
if (res[i].first == res[i - 1].first && res[i].second.first == res[i - 1].second.first &&
res[i].second.second == res[i - 1].second.second) {
continue;
}
if (res[i].second.first < 10) {
if (res[i].second.second < 10) {
cout << res[i].first << "-0" << res[i].second.first << "-0" << res[i].second.second << "\n";
} else {
cout << res[i].first << "-0" << res[i].second.first << "-" << res[i].second.second << "\n";
}
} else {
if (res[i].second.second < 10) {
cout << res[i].first << "-" << res[i].second.first << "-0" << res[i].second.second << "\n";
} else {
cout << res[i].first << "-" << res[i].second.first << "-" << res[i].second.second << "\n";
}
}
};
return 0;
}
2.蓝桥杯 2020 省 AB2 回文日期
题目描述
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 yyyymmdd
的格式写成一个 8 位数是 20200202
,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202
是“千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202
即 2021 年 12 月 2 日。
也有人表示 20200202
并不仅仅是一个回文日期,还是一个 ABABBABA
型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA
型的回文日期:21211212
即 2121 年12 月12 日。算不上“千年一遇”,顶多算“千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA
型的回文日期各是哪一天。
输入格式
输入包含一个八位整数 N,表示日期。
输出格式
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下 一个 ABABBABA
型的回文日期。
样例输入
20200202
样例输出
20211202
21211212
提示
对于所有评测用例,10000101 <= N <= 92200229,保证 N 是一个合法日期的 8 位数表示。
蓝桥杯 2020 第二轮省赛 A 组 G 题(B 组 G 题)。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leap(int y) {
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
return 1;
}
return 0;
}
bool check(int date) {
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if (month <= 0 || month >= 13) {
return false;
}
if (month != 2 && day > months[month]) {
return false;
}
if (month == 2 && day > months[month] + is_leap(year)) {
return false;
}
return true;
}
int main() {
int date;
cin >> date;
for (int i = date / 10000; i < 10000; i++) {
// 从目标日期的下一天开始便利
int x = i, r = i;
for (int j = 0; j < 4; j++) {
x = x * 10 + r % 10;
r /= 10;
}
if (check(x) && (x != date) && (x >= date)) {
cout << x << "\n";
break;
}
}
for (int i = date / 10000; i < 10000; i++) {
int a = i / 1000;
int b = i % 1000 / 100;
int c = i % 100 / 10;
int d = i % 10;
if (a == c && b == d && a != b) {
// 控制年份满足ABAB型
int x = i, r = i;
for (int j = 0; j < 4; j++) {
x = x * 10 + r % 10;
r /= 10;
}
if (check(x) && (x != date) && (x >= date)) {
cout << x << "\n";
break;
}
}
}
return 0;
}
3.NOIP2016 普及组 回文日期
题目描述
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用 8 位数字表示一个日期,其中,前 4 位代表年份,接下来 2 位代表月份,最后 2 位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。
牛牛认为,一个日期是回文的,当且仅当表示这个日期的 8 位数字是回文的。现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。
一个 8 位数字是回文的,当且仅当对于所有的 i(1 <= i <= 8)从左向右数的第 i 个数字和第 9-i 个数字(即从右向左数的第 i 个数字)是相同的。
例如:
- 对于 2016 年 11 月 19 日,用 8 位数字 20161119 表示,它不是回文的。
- 对于 2010 年 1 月 2 日,用 8 位数字 20100102 表示,它是回文的。
- 对于 2010 年 10 月 2 日,用 8 位数字 20101002 表示,它不是回文的。
每一年中都有 12 个月份:
其中,1, 3, 5, 7, 8, 10, 12 月每个月有 31 天;4, 6, 9, 11 月每个月有 30 天;而对于 2 月,闰年时有 29 天,平年时有 28 天。
一个年份是闰年当且仅当它满足下列两种情况其中的一种:
- 这个年份是 4 的整数倍,但不是 100 的整数倍;
- 这个年份是 400 的整数倍。
例如:
- 以下几个年份都是闰年:2000, 2012, 2016。
- 以下几个年份是平年:1900, 2011, 2014。
输入格式
两行,每行包括一个 8 位数字。
第一行表示牛牛指定的起始日期。
第二行表示牛牛指定的终止日期。
保证 date1 和 date2 都是真实存在的日期,且年份部分一定为 4 位数字,且首位数字不为 0。
保证 date1 一定不晚于 date2 。
输出格式
一个整数,表示在 date1 和 date2 之间,有多少个日期是回文的。
样例1
样例输入1
20110101
20111231
样例输出1
1
样例2
样例输入2
20000101
20101231
样例输出2
2
提示
【样例说明】
对于样例 1,符合条件的日期是 20111102。
对于样例 2,符合条件的日期是 20011002 和 20100102。
【子任务】
对于 60% 的数据,满足 date1 = date2。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leap(int y) {
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
return 1;
}
return 0;
}
bool check(int date) {
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if (month <= 0 || month >= 13) {
return false;
}
if (month != 2 && day > months[month]) {
return false;
}
if (month == 2) {
if (day > months[2] + is_leap(year)) {
return false;
}
}
return true;
}
int main() {
int date1, date2;
cin >> date1 >> date2;
int res = 0;
for (int i = 0; i < 10000; i++) {
int x = i, r = i;
for (int j = 0; j < 4; j++) {
x = x * 10 + r % 10;
r /= 10;
}
if (x >= date1 && x <= date2 && check(x)) {
res++;
}
}
cout << res << "\n";
return 0;
}
4.日期计算
题目描述
给定一个年份 y 和一个整数 d,问这一年的第 d 天是几月几日?
注意闰年的 2 月有 29 天。
满足下面条件之一的是闰年:
- 年份是 4 的整数倍,而且不是 100 的整数倍;
- 年份是 400 的整数倍。
输入格式
输入的第一行包含一个整数 y,表示年份,年份在 1900 到 2015 之间(包含 1900 和 2015)。
输入的第二行包含一个整数 d,d 在 1 至 365 之间。
输出格式
输出两行,每行一个整数,分别表示答案的月份和日期。
数据范围
1900 ≤ y ≤ 2015,
1 ≤ d ≤ 365
输入样例1
2015
80
输出样例1
3
21
输入样例2
2000
40
输出样例2
2
9
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int temp = 1;
int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leap(int y) {
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
return 1;
}
return 0;
}
int main() {
int year, day;
cin >> year >> day;
while (day > months[temp]) {
if (temp == 2) {
day -= months[temp] + is_leap(year);
} else {
day -= months[temp];
};
temp++;
}
if(day == 0) {
if(temp - 1 == 2) {
cout << temp - 1 << "\n" << months[temp - 1] + is_leap(year) << "\n";
}
else {
cout << temp - 1 << "\n" << months[temp - 1] << "\n";
}
}
else {
cout << temp << "\n" << day << "\n";
}
return 0;
}
5.日期差值
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
输入格式
输入包含多组测试数据。
每组数据占两行,分别表示两个日期,形式为 YYYYMMDD
。
输出格式
每组数据输出一行,即日期差值。
数据范围
年份范围[1, 9999] , 保证输入日期合法,测试数据的组数不超过 100。
输入样例
20110412
20110422
输出样例
11
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int months[] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leapyear(int x) {
if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0)) {
return 1;
}
return 0;
}
int getdays(int y, int m) {
if (m == 2) {
return months[2] + is_leapyear(y);
}
return months[m];
}
int calc(int year, int month, int day) {
int res = 0;
for (int i = 1; i < year; i++) {
res += 365 + is_leapyear(i);
}
for (int i = 1; i < month; i++) {
res += getdays(year, i);
}
res += day;
return res;
}
int main() {
int y1, y2, m1, m2, d1, d2;
while (~scanf("%4d%2d%2d\n%4d%2d%2d", &y1, &m1, &d1, &y2, &m2, &d2)) {
printf("%d\n", 1 + abs(calc(y1, m1, d1) - calc(y2, m2, d2)));
}
return 0;
}
如果有其它日期问题的相关题目,也可以分享到评论区owo~
Comments | NOTHING