开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情
今天来写一些蓝桥杯的一种常见问题,日期问题是蓝桥杯常见的一种问题,虽然不难,但是我写的代码几乎没有低于100行的qaq,所以我感觉还是有必要整理一下,日期问题一般都是模拟,虽然说代码长,但是呢,很容易发现问题,也是拿分的好题型,就是说有点难ac(bushi)! 话不多说,来看题: 先来看一道普及组的蓝桥杯原题:也是回文日期的一种题型
[NOIP2016 普及组] 回文日期
题目背景
NOIP2016 普及组 T2
题目描述
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用 位数字表示一个日期,其中,前 位代表年份,接下来 位代表月份,最后 位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。
牛牛认为,一个日期是回文的,当且仅当表示这个日期的 位数字是回文的。现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。
一个 位数字是回文的,当且仅当对于所有的 ()从左向右数的第 个数字和第 个数字(即从右向左数的第 个数字)是相同的。
例如:
- 对于 2016 年 11 月 19 日,用 位数字 表示,它不是回文的。
- 对于 2010 年 1 月 2 日,用 位数字 表示,它是回文的。
- 对于 2010 年 10 月 2 日,用 位数字 表示,它不是回文的。
每一年中都有 个月份:
其中, 月每个月有 天; 月每个月有 天;而对于 月,闰年时有 天,平年时有 天。
一个年份是闰年当且仅当它满足下列两种情况其中的一种:
- 这个年份是 的整数倍,但不是 的整数倍;
- 这个年份是 的整数倍。
例如:
- 以下几个年份都是闰年:。
- 以下几个年份是平年:。
输入格式
两行,每行包括一个 位数字。
第一行表示牛牛指定的起始日期。
第二行表示牛牛指定的终止日期。
保证 和 都是真实存在的日期,且年份部分一定为 位数字,且首位数字不为 。
保证 一定不晚于 。
输出格式
一个整数,表示在 和 之间,有多少个日期是回文的。
样例 #1
样例输入 #1
20110101
20111231
样例输出 #1
1
样例 #2
样例输入 #2
20000101
20101231
样例输出 #2
2
提示
【样例说明】
对于样例 1,符合条件的日期是 。
对于样例 2,符合条件的日期是 和 。
【子任务】
对于 的数据,满足 。
分析
刚接触这种问题,菜菜视角(我):暴力枚举不就行了?,直接枚举一下两个数,看着感觉是的复杂度,但是貌似其实问题不是这么简单,因为我后来发现,还要把八位数给分解,因此这个复杂度比较危险,所以说(别问我怎么知道的,也不知道是谁试了然后TLE了),后来总一语点醒梦中人,虽然是八位数,但是只有年啊,而且最多只有个会问日期啊,只要挨个判断就行了,然后给的那两个八位数,如果对应年份有回文日期且合法,那么我们就可以算进去,否则剪掉。代码实现过程也很简单,主要包括
判断年份所应该对应的日期是多少 判断平年闰年然后看前两位数字对应的月和末两位数字对应的天 特判给的起始八位数和末尾八位数前四位对应的年份是否回文,再看回文日期是否在所给范围之中。
代码
代码还是比较冗长的
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
bool check(int x){//判断平年闰年
if(x%4==0 || (x%100!=0 && x%400==0)) return true;
else return false;
}
int di(int x){//将年份对应的回文月日用四位数表示出来
int y=0;
int d[10];
int cnt=0;
while(x){
d[++cnt]=x%10;
x/=10;
}
for(int i=1;i<=4;i++){
y+=d[i]*pow(10,4-i);
}
return y;
}
bool panm(int m){//判断月份是31天还是30天
if(m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12) return true;
else return false;
}
int main(){
int y1,y2;
cin>>y1>>y2;
int y3=y1/10000;//取年份
int y4=y2/10000;//取年份
int cnt=0;
for(int i=y3;i<=y4;i++){
bool ok=0;
int hz=di(i);
int mo=hz/100;
int day=hz%100;
if(mo>12 || mo<=0) continue;
else{
if(mo==1 || mo==3 || mo==5 || mo==7 || mo==8 || mo==10 || mo==12){
if(day>=1 && day<=31){
ok=1;
cnt++;
}
}
else if(mo==2){
if(check(i)){
if(day>=1 && day<=29){
ok==1;
cnt++;
}
}
else{
if(day>=1 && day<=28){
ok==1;
cnt++;
}
}
}
else{
if(day>=1 && day<=30){
ok=1;
cnt++;
}
}
}
if(i==y3 && ok==1){//这里就是看满不满足在所给日期内
if(di(i)<y1%10000) cnt--;
}
if(i==y4 && ok==1){//这里就是看满不满足在所给日期内
if(di(i)>y2%10000) cnt--;
}
}
cout<<cnt<<endl;
}
[蓝桥杯 2020 省 AB2] 回文日期
题目描述
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 yyyymmdd 的格式写成一个 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是“千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年12 月12 日。算不上“千年一遇”,顶多算“千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
输入格式
输入包含一个八位整数 ,表示日期。
输出格式
输出两行,每行 个八位数。第一行表示下一个回文日期,第二行表示下
一个 ABABBABA 型的回文日期。
样例 #1
样例输入 #1
20200202
样例输出 #1
20211202
21211212
提示
对于所有评测用例,,保证 是一个合法日期的 位数表示。
蓝桥杯 2020 第二轮省赛 A 组 G 题(B 组 G 题)。 由这道题我们引出了蓝桥杯的回文日期,其实就是在输出上变化了一下,这个代码就要在有些地方上变一下,具体如下:由于这题要输出形如abab型的回文日期,于是在我们找到第一个回文日期之和,先要判断这个日期是不是符合abab型的回文日期,如果是我们把当前日期输出两遍就ok了,如果不是,我们再去找下一个就是满足月份等于天数的日期即可。 代码如下:
代码
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
bool check(int x){
if(x%4==0 || (x%100!=0 && x%400==0)) return true;
else return false;
}
int di(int x){
int y=0;
int d[10];
int cnt=0;
while(x){
d[++cnt]=x%10;
x/=10;
}
for(int i=1;i<=4;i++){
y+=d[i]*pow(10,4-i);
}
return y;
}
bool panm(int m){
if(m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12) return true;
else return false;
}
int main(){
bool ok1=0,ok2=0;
int y1;
cin>>y1;
int y3=y1/10000;
int cnt=0;
for(int i=y3;;i++){
int rr=i;
bool ok=0;
int hz=di(i);
int mo=hz/100;
int day=hz%100;
if(mo>12 || mo<=0) continue;
else{
if(mo==1 || mo==3 || mo==5 || mo==7 || mo==8 || mo==10 || mo==12){
if(day>=1 && day<=31){
ok=1;
}
}
else if(mo==2){
if(check(i)){
if(day>=1 && day<=29){
// cout<<day<<endl;
ok=1;
}
}
else{
if(day>=1 && day<=28){
ok=1;
}
}
}
else{
if(day>=1 && day<=30){
ok=1;
}
}
}
// cout<<day<<endl;
if(i==y3 && ok==1){
if(di(i)>=y1%10000){
if(mo<=9) rr*=10;
cout<<rr<<di(i)<<endl;
ok1=1;
}
}
if(i==y3 && ok==1 && mo==day){
if(di(i)>=y1%10000){
cout<<rr<<di(i)<<endl;
break;
}
}
if(i!=y3){
if(ok==1 && !ok1){
if(mo<=9) rr*=10;
cout<<rr<<di(i)<<endl;
ok1=1;
}
}
if(i!=y3){
if(ok==1 && day==mo){
if(mo<=9 && rr<10000) rr*=10;
cout<<rr<<di(i)<<endl;
break;
}
}
}
}
接下来这题也是日期问题,但是不是回文日期
[蓝桥杯 2017 省 B] 日期问题
题目描述
小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式
一个日期,格式是 AA/BB/CC。()
输出格式
输出若干个不相同的日期,每个日期一行,格式是 yyyy-MM-dd。多个日期按从早到晚排列。
样例 #1
样例输入 #1
02/03/04
样例输出 #1
2002-03-04
2004-02-03
2004-03-02
分析
初次接触这题的时候,我以为这是一个特别难的题,其实这确实是个特别难(模拟)的题,(个人感觉)!不过不同于刚开始,这次我有思路,其实就是一一判断3种情况有没有可能,最后输出,如果可能重复就舍弃!
代码
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
bool check(int x){
if(x%400==0 || (x%4==0 && x%100!=0)) return true;
else return false;
}
struct date{
int y,m,d;
}day[10];
bool cmp(date aa,date bb){
if(aa.y==bb.y){
return aa.m<bb.m;
if(aa.m<bb.m){
return aa.d<bb.d;
}
}
return aa.y<bb.y;
}
int main(){
bool ok1=0,ok2=0,ok3=0;
string s;
cin>>s;
int a[10];
a[1]=s[0]-'0';
a[2]=s[1]-'0';
a[3]=s[3]-'0';
a[4]=s[4]-'0';
a[5]=s[6]-'0';
a[6]=s[7]-'0';
int hz=a[1]*10+a[2];
int zz=a[3]*10+a[4];
int dz=a[5]*10+a[6];
int year;
if(hz>=0 && hz<=59) year=hz+2000;
if(hz>=60 && hz<=99) year=hz+1900;
if(zz>=1 && zz<=12){
if(zz==2){
if(check(year)){
if(dz>=1 && dz<=29){
ok1=1;
}
}
else{
if(dz>=1 && dz<=28){
ok1=1;
}
}
}
else if(zz==4 || zz==6 || zz==9 || zz==11){
if(dz>=1 && dz<=30) ok1=1;
}
else{
if(dz>=1 && dz<=31) ok1=1;
}
}
//cout<<year<<"-"<<s[3]<<s[4]<<"-"<<s[6]<<s[7]<<endl;
if(ok1==1){
day[1].y=year,day[1].m=zz,day[1].d=dz;
}
hz=a[5]*10+a[6];
zz=a[1]*10+a[2];
//cout<<zz<<endl;
dz=a[3]*10+a[4];
if(hz>=0 && hz<=59) year=hz+2000;
if(hz>=60 && hz<=99) year=hz+1900;
if(zz>=1 && zz<=12){
//cout<<ok2<<endl;
if(zz==2){
if(check(year)){
if(dz>=1 && dz<=29){
ok2=1;
// cout<<ok2<<endl;
}
}
else{
if(dz>=1 && dz<=28){
ok2=1;
//cout<<ok2<<endl;
}
}
}
else if(zz==4 || zz==6 || zz==9 || zz==11){
if(dz>=1 && dz<=30) ok2=1;
}
else{
if(dz>=1 && dz<=31) ok2=1;
}
}
if(ok2==1){
day[2].y=year,day[2].m=zz,day[2].d=dz;
//cout<<year<<"-"<<s[0]<<s[1]<<"-"<<s[3]<<s[4]<<endl;
}
hz=a[5]*10+a[6];
zz=a[3]*10+a[4];
dz=a[1]*10+a[2];
if(hz>=0 && hz<=59) year=hz+2000;
if(hz>=60 && hz<=99) year=hz+1900;
if(zz>=1 && zz<=12){
if(zz==2){
if(check(year)){
if(dz>=1 && dz<=29){
ok3=1;
}
}
else{
if(dz>=1 && dz<=28){
ok3=1;
}
}
}
else if(zz==4 || zz==6 || zz==9 || zz==11){
if(dz>=1 && dz<=30) ok3=1;
}
else{
if(dz>=1 && dz<=31) ok3=1;
}
}
// cout<<year<<"-"<<s[3]<<s[4]<<"-"<<s[0]<<s[1]<<endl;
if(ok3==1){
day[3].y=year,day[3].m=zz,day[3].d=dz;
}
sort(day+1,day+4,cmp);
//if()
for(int i=1;i<=3;i++){
if((day[i].y==day[i-1].y && day[i].m==day[i-1].m && day[i].d==day[i-1].d) || (day[i].y==day[i-2].y && day[i].m==day[i-2].m && day[i].d==day[i-2].d)) continue;
if(day[i].d==0) continue;
printf("%d-%02d-%02d\n",day[i].y,day[i].m,day[i].d);
}
return 0;
}