专题一:日期问题
目录
前言
在专题一种我们主要讲解关于日期的问题,比较基础但是一定要掌握!!在蓝桥杯竞赛中,常会考到一些日期日历的问题,出现在填空题或者编程的前几题,因此巩固好基础更加有助于我们在比赛中遇到类似的题时游刃有余。下面来枚举一些例题与蓝桥杯的真题。格式会按照:题目—题解—知识点,十分清晰!!废话不多说,先上模板!!
模板
非常重要!!可以说背下来可以做出来%90的日期日历的问题!
#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
代码
#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
然后判断:
- 整个八位数构成的日期是否合法
- 是否在范围内
本题思维在于枚举所有回文数再去筛选出符合要求的。
知识点:
- 判断日期是否合法的模板
- 回文串转换算法
2、日期识别
代码
#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;
}
题解
本题主要就是枚举,再加上一些字符串处理的知识,并没有什么思维上的难度。
知识点:
- substr函数:返回从某个位置后指定长度的子串
- 字符转成数字的操作
3、日期类
代码
#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,日也是一样的做法。
知识点:
- 算天数模板的运用
- 判断闰年
4、打印日期
代码
#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月的天数。
知识点:
- 格式输出大法:printf(“%04d-%02d-%02d\n”,y,m,d);
- 判断闰年
5、日期
代码
#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];
}
题解
本题思维点在于把星期四当成第一天,然后计算出给出的日期与第一天的差值,再利用取模的算法求出是星期几,如果对取模算法不熟悉的话需要自行在草稿纸上模拟一遍,并记下这个结论。
知识点:
- 打表,将星期四作为第一天
- 取模运算求出是星期几
6、日期计算
代码
解法一:模板法
#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;
}
思维法:
#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;
}
题解
本题考察日期计算的方法,可以套用模板,也可以用思维法减少代码量,看个人喜好。
知识点:
- 得到某年某月某日的天数
- 计算给定年月日,经过n天后对应的日期
7、特殊年份—蓝桥杯十二届真题
代码
#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
代码
#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,在去判断是否符合格式.
最后找到两个答案就输出即可。
知识点:
- 回文子串构造
- 判断合法日期
- 判断是否符合格式
总结
以上的题基本包含了所有会考到的日期日历问题,各位一定要先把模板背熟,再去写例题,不会的题一定要
好好琢磨题解的思维以及需要掌握的知识点是否已经烂熟于心。开篇大吉,预祝各位考生考出好成绩!!