目录
- 引言
- 概念
- 一、日期差值
- 二、日期问题
- 三、回文日期 I
- 四、回文日期 II
- 五、日期计算
引言
日期问题在蓝桥杯中只要把常见的题型掌握明白了,把逻辑给写清楚明白,基本上是很简单的,再就是多做题,题型多见,做熟练,基本上问题不大,加油!
概念
日期问题:
问题无非就是该日期是否有效,是否回文,日期差值,日期计算这些问题,多做做题,基本上很简单的
答题模板:
只要是日期问题,这样写既清楚明白,又不会乱不会缺啥,再根据题意补充即可。
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;
}