专题一:日期问题

前言

在专题一种我们主要讲解关于日期的问题,比较基础但是一定要掌握!!在蓝桥杯竞赛中,常会考到一些日期日历的问题,出现在填空题或者编程的前几题,因此巩固好基础更加有助于我们在比赛中遇到类似的题时游刃有余。下面来枚举一些例题与蓝桥杯的真题。格式会按照:题目—题解—知识点,十分清晰!!废话不多说,先上模板!!

image.png

模板

非常重要!!可以说背下来可以做出来%90的日期日历的问题!

C++
复制代码
#include <iostream> using namespace std; int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 判断日期的合法性 bool check_valid(int date) //形如20210305 { int year = date / 10000; int month = date % 10000 / 100; int day = date % 100; if (month <= 0 || month >= 13) return false; if (day == 0 || month != 2 && day > months[month]) return false; if (month == 2) { int leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); if (day > 28 + leap) return false; } return true; } // 得到某年某月的天数 int get(int year, int month) { if (month != 2) return months[month]; else { // 2月 int leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); return 28 + leap; } } // 判断两个日期之间有多少个回文日期 int get(int date1, int date2, int k) //k使函数签名不同从而编译通过 { int ans = 0; for (int i = 1000; i < 10000; i++) { int date = i, x = i; for (int j = 0; j < 4; j++) date = date * 10 + x % 10, x /= 10; //根据年份构造出回文日期 if (date1 <= date && date <= date2 && check_valid(date)) ans++; } return ans; } // 给定年月日,经过n天后对应的日期 void pass(int y, int m, int d, int n) { while (n--) { d++; if (d > get(y, m)) m++, d = 1; if (m > 12) y++, m = 1; } printf("%d-%02d-%02d\n", y, m, d); }

1、回文日期-1

image_8DQXwLdh4f.png

image_F5qCyEFE0r.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; //判断日期是否合法的模板,背诵!! bool check(int date) { int year=date/10000; int month= date%10000/100; int day = date%100; if(!month||month>=13||!day) return false; if(month!=2&&day>months[month]) return false; if(month==2) { bool leap = year%4==0 &&year %100!=0 || year %400==0; if(day>leap+28) return false; } return true; } int main() { int data1,data2; cin>>data1>>data2; int res=0; for(int i=0;i<10000;i++) { int x=i,r=i; for(int j=0;j<4;j++) r=r*10+x%10,x=x/10;//回文串转换的算法 if(r>=data1&& r<=data2 && check(r)) res++; } cout<<res<<endl; return 0; }

题解

由于只有八位数,且回文串左右对称,因此可以只枚举左边,这样只需要枚举0~9999

然后判断:

  1. 整个八位数构成的日期是否合法
  2. 是否在范围内

本题思维在于枚举所有回文数再去筛选出符合要求的。

知识点:

  1. 判断日期是否合法的模板
  2. 回文串转换算法

2、日期识别

image_kw0EJjwrmn.png

image_wTHGGecViR.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; string month[13]={"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; int main() { string st; int m,d1,d2; cin>>st; for(int i=1;i<=12;i++) if(st.substr(0,3)==month[i]) { m=i; break; } d1=st[3]-'0'; d2=st[4]-'0'; cout<<m<<" "; if(d1!=0) cout<<d1; cout<< d2; }

题解

本题主要就是枚举,再加上一些字符串处理的知识,并没有什么思维上的难度。

知识点:

  1. substr函数:返回从某个位置后指定长度的子串
  2. 字符转成数字的操作

3、日期类

image_xkj-5iiRs9.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int main() { int n,y,m,d; cin>>n; while(n--){ cin>>y>>m>>d; if(y%4==0&&y%100!=0||y%400==0)a[2]=29; else a[2]=28; d++; if(d>a[m]){ m++; d=1; } if(m>12){ m=1; y++; } if(y<10)cout<<0; cout<<y<<'-'; if(m<10)cout<<0; cout<<m<<'-'; if(d<10)cout<<0; cout<<d; cout<<endl; } return 0; }

题解

变量是:y=year m=month d=day

然后我们判断,只要我们的天数大于了这个月的天数,我们就要把月份m++,并且把日回到1号 同理只要我们的月数大于了12,我们就要把年份y++,并且把月份回到1月

接下来我们还要考虑一个问题,就是一位数前加0(输出格式) 我们只要一次判断即可:只要y是一位数,先输出个0,日也是一样的做法。

知识点:

  1. 算天数模板的运用
  2. 判断闰年

4、打印日期

image_UxZ4jtKlmW.png

image_ixcooYY5Yp.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int main() { int y,d; //输入多行数据 while(cin>>y>>d){ //获得二月的天数 if(y%4==0&&y%100!=0||y%400==0)a[2]=29; else a[2]=28; int m=1; while(d>0){ if(d-a[m]<=0)break; else{ d-=a[m]; m++; } } printf("%04d-%02d-%02d\n",y,m,d);//数据宽度不足时用0填补 } }

题解

先把每个月的天数给列下来,再判断闰年。 最后我们来统计是几月几日,如果减去m月的天数,就比0要小了,我们就赶快退出 如果不会的话,月份+1,并且减去m月的天数。

知识点:

  1. 格式输出大法:printf("%04d-%02d-%02d\n",y,m,d);
  2. 判断闰年

5、日期

image_5wlbv3TwGD.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; int a[13]={0,31,29,31,30,31,30,31,31,30,31,30,31}; string week[7]={"Thursday","Friday","Saturday","Sunday","Monday","Tuesday","Wednesday",}; int main() { int n,m,day1=0,day2=0; cin>>n>>m; for(int i=1;i<4;i++)day1+=a[i]; day1+=12; for(int i=1;i<n;i++)day2+=a[i]; day2+=m; cout<<week[(day2-day1)%7]; }

题解

本题思维点在于把星期四当成第一天,然后计算出给出的日期与第一天的差值,再利用取模的算法求出是星期几,如果对取模算法不熟悉的话需要自行在草稿纸上模拟一遍,并记下这个结论。

知识点:

  1. 打表,将星期四作为第一天
  2. 取模运算求出是星期几

6、日期计算

image_plw0op1pYi.png

image_nCOo4tQrC-.png

代码

解法一:模板法

C++
复制代码
#include <iostream> using namespace std; int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 得到某年某月的天数 int get(int year, int month) { if (month != 2) return months[month]; else { // 2月 int leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); return 28 + leap; } } // 给定年月日,经过n天后对应的日期 void pass(int y, int m, int d, int n) { while (n--) { d++; if (d > get(y, m)) m++, d = 1; if (m > 12) y++, m = 1; } printf("%d\n%d\n", m, d); } int main() { int y, n; cin >> y >> n; int m = 1, d = 0; pass(y, 1, d, n); return 0; }

思维法:

C++
复制代码
#include<bits/stdc++.h> using namespace std; int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int main() { int y,d; cin>>y>>d; if(y%4==0&&y%100!=0||y%400==0)a[2]=29;else a[2]=28; int x=0; while(d>0){ if(d-a[x]<=0)break; else{ d-=a[x]; x++; } } cout<<x<<'\n'<<d; }

题解

本题考察日期计算的方法,可以套用模板,也可以用思维法减少代码量,看个人喜好。

知识点:

  1. 得到某年某月某日的天数
  2. 计算给定年月日,经过n天后对应的日期

7、特殊年份—蓝桥杯十二届真题

image_xATHh4b7-k.png

代码

C++
复制代码
#include<bits/stdc++.h> using namespace std; int main() { int count=0; for(int i=0;i<5;i++) { string s; cin>>s; if(s[0]==s[2]&&s[3]-s[1]==1) { count++; } } cout<<count<<endl; }

题解

水题一套,只要会字符串处理即可AC

7、回文日期-2

image_gN7OPu6RwK.png

image_eT1jL6BF79.png

代码

C++
复制代码
#include <iostream> using namespace std; int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 判断日期的合法性 bool check_valid(int date) { int year = date / 10000; int month = date % 10000 / 100; int day = date % 100; if (month <= 0 || month >= 13) return false; if (day == 0 || month != 2 && day > months[month]) return false; if (month == 2) { int leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); if (day > 28 + leap) return false; } return true; } // 判断date是否满足ABABBABA形式 bool check(int date) { int year = date / 10000; int month = date % 10000 / 100; int day = date % 100; if (month % 10 == day / 10) return false; //A==B return false if ((month % 10 == day % 10) && (month / 10 == day / 10)) return true; return false; } bool st1, st2; int ans1, ans2; int main() { int date; cin >> date; int year = date / 10000; while (true) { int new_date = year, x = year; for (int i = 0; i < 4; i++) new_date = new_date * 10 + x % 10, x /= 10; //构造回文日期 if (new_date == date) //构造出来的是同一天 { year++; continue; } if (check_valid(new_date)) { if (!st1) st1 = true, ans1 = new_date; if (!st2 && check(new_date)) st2 = true, ans2 = new_date; } year ++; if (st1 && st2) break; //找到两个解则退出 } printf("%d\n%d", ans1, ans2); return 0; }

题解

本题需要找到两个符合题目的答案,第一个是回文子串,第二个符合格式的回文子串。

先构造回文子串

用函数判断是不是合法日期,如果不是就跳到下一个。 如果符合,那么第一个答案已经找到,即可标记为true,在去判断是否符合格式.

最后找到两个答案就输出即可。

知识点:

  1. 回文子串构造
  2. 判断合法日期
  3. 判断是否符合格式

总结

以上的题基本包含了所有会考到的日期日历问题,各位一定要先把模板背熟,再去写例题,不会的题一定要

好好琢磨题解的思维以及需要掌握的知识点是否已经烂熟于心。开篇大吉,预祝各位考生考出好成绩!!

image.png

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP