引言
日期问题在蓝桥杯中只要把常见的题型掌握明白了,把逻辑给写清楚明白,基本上是很简单的,再就是多做题,题型多见,做熟练,基本上问题不大,加油!
概念
日期问题:
问题无非就是该日期是否有效,是否回文,日期差值,日期计算这些问题,多做做题,基本上很简单的
答题模板:
只要是日期问题,这样写既清楚明白,又不会乱不会缺啥,再根据题意补充即可。
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false; // 一般年份都是正确的
return d <= get_month_day(y,m);
}
bool check(int y, int m, int d)
{
if(!is_vaild(y,m,d)) return false;
//该题逻辑
//......
}
一、日期差值
标签:日期问题
思路:
计算从公元
1
1
1 年
1
1
1 月
1
1
1 日到
d
a
t
e
1
date1
date1 有多少天,最后两个天数做差再加一即可。
题目描述:
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
输入格式
输入包含多组测试数据。
每组数据占两行,分别表示两个日期,形式为 YYYYMMDD。
输出格式
每组数据输出一行,即日期差值。
数据范围
年份范围 [1,9999],保证输入日期合法。测试数据的组数不超过 100。
输入样例:
20110412
20110422
输出样例:
11
示例代码:
#include <bits/stdc++.h>
using namespace std;
int date1, date2;
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false; // 一般年份都是正确的
return d <= get_month_day(y,m);
}
int get_total_day(int y, int m, int d)
{
int res = 0;
for(int i = 1; i < y; ++i) res += 365 + is_leap(i);
for(int i = 1; i < m; ++i) res += get_month_day(y,i);
return res + d;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
while(~scanf("%d", &date1))
{
scanf("%d", &date2);
int y1,m1,d1, y2,m2,d2;
y1 = date1 / 10000, m1 = date1 % 10000 / 100, d1 = date1 % 100;
y2 = date2 / 10000, m2 = date2 % 10000 / 100, d2 = date2 % 100;
cout << abs(get_total_day(y1,m1,d1) - get_total_day(y2,m2,d2)) + 1 << endl; // 未指明大小
}
return 0;
}
二、日期问题
标签:日期问题
思路:
把日期当作数字,在该数字的范围内,首先判断该日期是否有效,再加上本题的判断条件,最后输出即可。
题目描述:
小明正在整理一批历史文献。这些历史文献中出现了很多日期。
小明知道这些日期都在1960年1月1日至2059年12月31日。
令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式
一个日期,格式是”AA/BB/CC”。
即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。
输出格式
输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。
多个日期按从早到晚排列。
数据范围
0≤A,B,C≤9
输入样例:
02/03/04
输出样例:
2002-03-04
2004-02-03
2004-03-02
示例代码:
#include <bits/stdc++.h>
using namespace std;
int a, b, c;
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false;
return d <= get_month_day(y,m);
}
bool check(int y, int m, int d)
{
if(!((a == y%100 && b == m && c == d) || (a == m && b == d && c == y%100)
|| (a == d && b == m && c == y%100)))
return false;
if(!is_vaild(y,m,d)) return false;
return true;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
scanf("%02d/%02d/%02d", &a, &b, &c);
for(int date = 19600101; date <= 20591231; ++date)
{
int y = date / 10000, m = date % 10000 / 100, d = date % 100;
if(check(y,m,d)) printf("%04d-%02d-%02d\n", y,m,d);
}
return 0;
}
三、回文日期 I
标签:日期问题
思路:
如果跟上道题一样枚举把日期当作数来枚举的话,如果取极限的话,时间是会超时的,因为要枚举
1
0
8
10 ^ 8
108 个数。一般这种回文日期什么的都是可以光枚举年,然后构造出一个回文日期,看该日期是否在所需范围内,并且是有效日期,这样时间复杂度就就缩减到
O
(
1
0
4
)
O(10 ^ 4)
O(104) 了。
题目描述:
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用 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 表示,它不是回文的。
输入格式
输入包括两行,每行包括一个 8 位数字。
第一行表示牛牛指定的起始日期 date1,
第二行表示牛牛指定的终止日期 date2。保证 date1 和 date2 都是真实存在的日期,且年份部分一定为 4 位数字,且位数字不为 0。
保证 date1 一定不晚于 date2。
输出格式
输出共一行,包含一个整数,表示在 date1 和 date2 之间,有多少个日期是回文的。
输入样例:
20110101
20111231
输出样例:
1
示例代码:
#include <bits/stdc++.h>
using namespace std;
int date1, date2;
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false;
return d <= get_month_day(y,m);
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int res = 0;
cin >> date1 >> date2;
for(int date = 1; date <= 9999; ++date)
{
int t = date, x = date;
while(t)
{
x = x * 10 + t % 10;
t /= 10;
}
if(x < date1 || x > date2) continue;
int y = x / 10000, m = x % 10000 / 100, d = x % 100;
if(!is_vaild(y,m,d)) continue;
res++;
}
cout << res << endl;
return 0;
}
四、回文日期 II
标签:日期问题
思路:
根据上一题的思路,可以只遍历年,然后构造出回文日期,然后判断是否是在规定日期后,并且是否有效,最后再判断是否是
A
B
A
B
A
B
A
B
ABABABAB
ABABABAB 型的,另外只需输出一个,给个
f
l
a
g
flag
flag 标记即可。
题目描述:
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。
因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。
我们称这样的日期是回文日期。
有人表示 20200202 是“千年一遇” 的特殊日子。
对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。
对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。
算不上“千年一遇”,顶多算“千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
注意
下一个回文日期和下一个 ABABBABA 型的回文日期可能是同一天。
ABABBABA 型的回文日期,需要满足 A≠B。
输入格式
输入包含一个八位整数 N,表示日期。
输出格式
输出两行,每行 1 个八位数。
第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
数据范围
对于所有评测用例,10000101≤N≤89991231,保证 N 是一个合法日期的 8 位数表示。
输入样例:
20200202
输出样例:
20211202
21211212
示例代码:
#include <bits/stdc++.h>
using namespace std;
int date1;
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false;
return d <= get_month_day(y,m);
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> date1;
bool flag1 = true, flag2 = true;
for(int year = date1 / 10000; year <= 9999; ++year)
{
int t = year, x = year;
while(t)
{
x = x * 10 + t % 10;
t /= 10;
}
if(x <= date1) continue;
int y = x / 10000, m = x % 10000 / 100, d = x % 100;
if(!is_vaild(y,m,d)) continue;
if(flag1) cout << x << endl, flag1 = false;
if(flag2 && y / 100 == y % 100 && y / 1000 != y % 10) cout << x << endl, flag2 = false;
if(!flag1 && !flag2) break;
}
return 0;
}
五、日期计算
标签:日期问题
思路:
直接枚举每一个月,然后比较天数,如果大了说明是下一个月的,天数减去当前月的总天数,再跟下一个月的天数比较。
题目描述:
给定一个年份 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 <bits/stdc++.h>
using namespace std;
int year, d;
const int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y)
{
if(y % 400 == 0 || y % 4 == 0 && y % 100 != 0) return true;
return false;
}
int get_month_day(int y, int m)
{
if(m == 2) return days[m] + is_leap(y);
return days[m];
}
bool is_vaild(int y, int m, int d)
{
if(m < 1 || m > 12 || d < 1 || d > 31) return false;
return d <= get_month_day(y,m);
}
int main()
{
cin >> year >> d;
int month, day;
for(int i = 1; i <= 12; ++i)
{
int t = get_month_day(year, i);
if(d <= t)
{
month = i, day = d;
break;
}
d -= t;
}
cout << month << endl;
cout << day << endl;
return 0;
}