【蓝桥杯】日期类与时间类问题


日期类与时间类问题

考点:模拟 、枚举

1.判断闰年

闰年满足的条件:

  • 能被4整除且不能被100整除
  • 或者能被400整除
bool is_run(int year)
{
	if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return true;
	else return false;
}

2.日期合法判断

注:平年二月有28天,闰年2月有29天。

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月有28天

// 判断该回文串是否为合理日期
bool check(int date)
{
    int year = date / 10000;
    int month = date / 100 % 100;
    int day = date % 100;
    if(month == 0 || month >= 13 || day == 0) return false;
    if(month != 2 && day > days[month]) return false;
    
    if(month == 2)// 2月特判
    {
        int leap = 0;// 0表示平年, 1表示闰年
        if(leap_year(year))
            leap = 1;
        if(day > 28 + leap) return false;    
    }
    
    return true;
}
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月28天

bool is_run(int year)
{
    if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
    else return false;
}
// 判断日期是否合理(date:xxxx - xx - xx 年月日)
bool check(int date)
{
    int year = date / 10000;
    int month = date / 100 % 100;
    int day = date % 100;
    
    if(month == 0 || month >= 13 || day == 0) return false;// 初次判断月日是否合理
    if(month != 2 && days > days[month]) return false;
    if(month == 2)// 特判2月康康是闰年还是平年:闰年29天,平年28天
    {
        int leap = 0;
        if(is_run(year))// 0表示平年, 1表示闰年
            	leap = 1;
        if(day > 28 + leap) return false;
    }
    return true;
    
}

巩固练习——日期类

1. 回文日期

【题目链接】466. 回文日期 - AcWing题库

(枚举,模拟) O(10^4)
由于只有八位数,而且回文串左右对称,因此可以只枚举左半边,另一边通过翻转得到即可。这样只需枚举 0∼9999总共一万个数,然后判断:

  • 整个八位数构成的日期是否合法;
  • 是否在范围内

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool is_run(int year)
{
    if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
    else return false;
}

bool check(int date)
{
    int year = date / 10000;
    int month = date / 100 % 100;
    int day = date % 100;
    if(month == 0 || month >= 13 || day == 0) return false;
    if(month != 2 && day > days[month]) return false;
    if(month == 2)// 特判2月
    {
        int leap = 0;
        if(is_run(year))
            leap = 1;
       if(day > 28 + leap) return false;     
    }
    return true;
}

int main()
{
    int date1, date2;
    cin >> date1 >> date2;
    
    int res = 0;
    for(int i = 1000; i <= 9999; i ++)
    {
        int date = i, tmp = i;
        // 1.翻转拼接为日期形式
        for(int j = 1; j <= 4; j ++) date = date * 10 + tmp % 10, tmp /= 10;
        // 2.判断8位日期(已经是回文串)是否合理
        if(date >= date1 && date <= date2 && check(date))
            res ++;
    }
    cout << res;
    
    return 0;
}

2.日期问题

【题目链接】1229. 日期问题 - AcWing题库

注意数据的读入和输出格式,推荐使用scanfprintf

思路:

枚举日期,判断是否满足题目的要即可,满足输出即可

  • 在题目给的范围内枚举所有日期
  • 判断是否满足日期个要求
    • 再满足日期要求的前提下,判断是否符合题目所给的三种格式即可

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool is_run(int year)
{
    if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
    else return false;
}

bool check(int date)
{
    int year = date / 10000;
    int month = date / 100 % 100;
    int day = date % 100;
    if(month == 0 || month >= 13 || day == 0) return false;
    if(month != 2 && day > days[month]) return false;
    if(month == 2)
    {
        int leap = 0;
        if(is_run(year)) leap = 1;
        if(day > leap + 28) return false;
    }
    return true;
}
int main()
{
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);
    
    //枚举所有日期:日期都在1960年1月1日至2059年12月31日。
    for(int i = 19600101; i <= 20592331; i ++)
    {
        int date = i;
        if(check(date))// 检查日期合法性
        {
            int year = date / 10000, month = date / 100 % 100, day = date % 100;
            //有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的
            if(year % 100 == a && month == b && day == c || // 年月日
               month == a && day == b && year % 100 == c || // 月日年
               day == a && month == b && year % 100 == c)   // 日月年
               {
                   // 不足两位会自动补0
                   printf("%d-%02d-%02d\n", year, month, day);
               }
        }
    }
    
    return 0;
}

3.回文日期

在这里插入图片描述

思路:同上题

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月有28天

// 判断是否为ABABBABA形
bool check2(int date)
{
    string s = to_string(date);
    
    if(s[0] == s[2]  && s[1] == s[3]) return true;
    else return false;
}

// 判断闰年
bool leap_year(int year)
{
    if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
    else return false;
}

// 判断该回文串是否为合理日期
bool check(int date)
{
    int year = date / 10000;
    int month = date / 100 % 100;
    int day = date % 100;
    if(month == 0 || month >= 13 || day == 0) return false;
    if(month != 2 && day > days[month]) return false;
    
    if(month == 2)// 2月特判
    {
        int leap = 0;// 0表示平年, 1表示闰年
        if(leap_year(year))
            leap = 1;
        if(day > 28 + leap) return false;    
    }
    
    return true;
}

int main()
{
    int date1;
    cin >> date1;
    
    int res1 = 0, res2;
    for(int i = date1 % 10000 + 1; i < 10000; i ++)
    {
        int x = i, date = i;
        for(int j = 0; j < 4; j ++) date = date * 10 + x % 10, x /= 10;// 将年份和年份的翻转拼接(一定是回文串)
        
        if(date > date1 && check(date))
        {
            if(!res1) res1 = date;// 由于是顺序枚举,第一个就是所求的下一个
            if(check2(date))//在回文日期的基础上:判断是否为ABABBABA
            {
                res2 = date;
                break;
            }
        }
    }
    
    cout << res1 << endl << res2;
    
    return 0;
}

巩固练习——时间类

1.航班时间

【题目链接】1231. 航班时间 - AcWing题库

本题的难点处理在于输入输出处理!

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

//           t1
// 去 :end1 - start1 = t + 时差
//           t2
// 回 :end2 - start2 = t - 时差
// 2t = (t1 + t2)
// 

int get_second(int h, int m, int sec)
{
    return h * 3600 + m * 60 + sec;
}

int get_time()
{
    string line;
    getline(cin, line);
    
    // 对应变化处理
    if(line.back() != ')') line += "(+0)";
    
    // 记住sscanf的用法
    int h1, m1, s1, h2, m2, s2, d;
    sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);// 从字符串中获取信息
    
    //将所有时间转化为距离当天(00:00:00)的秒数
    return get_second(h2, m2, s2) - get_second(h1, m1, s1) + d * 24 * 3600;
}


int main()
{
    int n;
    scanf("%d", &n);
    
    string line;
    getline(cin, line);// 跳过首行的回车空格
    
    while(n --)
    {
        // 求飞行时间
        int t = (get_time() + get_time()) / 2;
        
        // 格式变化
        int hour = t / 3600;
        int month = t % 3600 / 60;
        int sec = t % 3600 % 60;
        
        printf("%02d:%02d:%02d\n", hour, month, sec);
    }
    return 0;
}

2.时间显示

【题目链接】3416. 时间显示 - AcWing题库

对于时间,常用的方法就是模运算和除运算两种。

常用公式

// time:这里的单位为s
hour = time / 3600;
min = time % 3600 / 60;
sec = time % 3600 % 60;

注:对于模运算的理解,相当于过滤掉不需要的秒数。
比如说min = time % 3600 / 60;相当于要求出分钟是多少,就要把属于小时的秒数都过滤掉(减去),然后再对剩下的秒数除以60,得到分钟数。

思路:

这道题有一点变形。**由于不需要显示年月日,因此给的秒数应该先过滤掉输入年月日的秒数。**即time % (24 * 60 * 60)

又有一点,给的不是秒数,而是毫秒,因此要先除以1000变成秒数,再进行一系列操作。

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int main()
{
    LL hao_miao;
    cin >> hao_miao;
     
    LL time = hao_miao / 1000;// 将毫秒变成秒
    time = time % (24 * 60 * 60);// 过滤掉年月日的秒数
    
    LL hour = time / 3600;
    LL mi = time % 3600 / 60;
    LL sec = time % 3600 % 60;
    
    printf("%02lld:%02lld:%02lld", hour, mi, sec);
    
    
    return 0;
}
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值