【蓝桥杯C/C++】专题一:日期问题

专题一:日期问题

前言

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

模板

非常重要!!可以说背下来可以做出来%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

然后判断:

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

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

知识点:

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

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;
}

题解

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

知识点:

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

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,日也是一样的做法。

知识点:

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

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月的天数。

知识点:

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

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];
}

题解

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

知识点:

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

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;
}


题解

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

知识点:

  1. 得到某年某月某日的天数
  2. 计算给定年月日,经过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,在去判断是否符合格式.

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

知识点:

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

总结

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

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

在这里插入图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会喷火的小火龙

你的鼓励是我最大的创作动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值