蓝桥杯-日期问题

发布于 2024-04-05  110 次阅读


日期问题在蓝桥杯中出现很多次,总是变着花样去考,但是归根到底就是几个模板,本文给出一些代码模板和相关题目。

常用的代码模板:

一、天数定义

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

months数组定义为全局变量

二、闰年判断

代码模板

int is_leap(int year) {
    if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
        return 1;
    }
    return 0;
}

有人可能会问这里为什么不用bool类型函数,其实bool类型和int类型都可以,我这里设为int类型是为了后续更加方便

三、获取天数

代码模板

int getdays(int year, int month) {
    if (month == 2) {
        return months[2] + is_leap(year);
    }
    return months[month];
}




这里就调用了上述is_leap函数,如果为闰年直接就加1,否则加0,判断起来更为简单

日期问题的相关题目:

1.蓝桥杯 2017 省 B 日期问题

题目描述

小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。

比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。

给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入格式

一个日期,格式是 AA/BB/CC(0 <= A, B, C <= 9)

输出格式

输出若干个不相同的日期,每个日期一行,格式是 yyyy-MM-dd。多个日期按从早到晚排列。

样例 #1

样例输入 #1

02/03/04

样例输出 #1

2002-03-04  
2004-02-03  
2004-03-02

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
​
using namespace std;
​
int a, b, c;
vector<pair<int, pair<int, int>>> res;
​
const int months[13] = {
        0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
​
int is_leap(int x) {
    if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0)) {
        return 1;
    }
    return 0;
}
​
int getdays(int y, int m) {
    if (m == 2) {
        return months[2] + is_leap(y);
    }
    return months[m];
}
​
bool judge_y(int y) {
    if (y > 60) {
        return true;
    }
    return false;
}
​
bool judge_m(int m) {
    if (m <= 0 || m >= 13) {
        return false;
    }
    return true;
}
​
bool judge_d(int y, int m, int d) {
    if (d > 0 && d <= getdays(y, m)) {
        return true;
    }
    return false;
}
​
int main() {
    scanf("%d/%d/%d", &a, &b, &c);
    if (judge_y(a)) {
        if (judge_m(b) && judge_d(1900 + a, b, c)) {
            res.push_back({1900 + a, {b, c}});
        }
    } else {
        if (judge_m(b) && judge_d(2000 + a, b, c)) {
            res.push_back({2000 + a, {b, c}});
        }
    }
​
    if (c > 60) {
        if (a != b) {
            if (judge_m(a) && judge_d(1900 + c, a, b)) {
                res.push_back({1900 + c, {a, b}});
            }
            if (judge_m(b) && judge_d(1900 + c, b, a)) {
                res.push_back({1900 + c, {b, a}});
            }
        } else {
            if (judge_m(b) && judge_d(1900 + c, b, a)) {
                res.push_back({1900 + c, {b, a}});
            }
        }
​
    } else {
        if (a != b) {
            if (judge_m(a) && judge_d(2000 + c, a, b)) {
                res.push_back({2000 + c, {a, b}});
            }
            if (judge_m(b) && judge_d(2000 + c, b, a)) {
                res.push_back({2000 + c, {b, a}});
            }
        } else {
            if (judge_m(b) && judge_d(2000 + c, b, a)) {
                res.push_back({2000 + c, {b, a}});
            }
        }
​
    }
​
    sort(res.begin(), res.end());
​
    for (int i = 0; i < res.size(); i++) {
        if (res[i].first == res[i - 1].first && res[i].second.first == res[i - 1].second.first &&
            res[i].second.second == res[i - 1].second.second) {
            continue;
        }
​
        if (res[i].second.first < 10) {
            if (res[i].second.second < 10) {
                cout << res[i].first << "-0" << res[i].second.first << "-0" << res[i].second.second << "\n";
            } else {
                cout << res[i].first << "-0" << res[i].second.first << "-" << res[i].second.second << "\n";
            }
        } else {
            if (res[i].second.second < 10) {
                cout << res[i].first << "-" << res[i].second.first << "-0" << res[i].second.second << "\n";
            } else {
                cout << res[i].first << "-" << res[i].second.first << "-" << res[i].second.second << "\n";
            }
        }
    };
​
    return 0;
}




2.蓝桥杯 2020 省 AB2 回文日期

题目描述

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 yyyymmdd 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是“千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年12 月12 日。算不上“千年一遇”,顶多算“千年两遇”。

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

输入格式

输入包含一个八位整数 N,表示日期。

输出格式

输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下 一个 ABABBABA 型的回文日期。

样例输入

20200202

样例输出

20211202
21211212

提示

对于所有评测用例,10000101 <= N <= 92200229,保证 N 是一个合法日期的 8 位数表示。

蓝桥杯 2020 第二轮省赛 A 组 G 题(B 组 G 题)。

代码

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

using namespace std;

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

int is_leap(int y) {
    if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
        return 1;
    }
    return 0;
}

bool check(int date) {
    int year = date / 10000;
    int month = date % 10000 / 100;
    int day = date % 100;

    if (month <= 0 || month >= 13) {
        return false;
    }

    if (month != 2 && day > months[month]) {
        return false;
    }

    if (month == 2 && day > months[month] + is_leap(year)) {
        return false;
    }

    return true;
}

int main() {
    int date;
    cin >> date;

    for (int i = date / 10000; i < 10000; i++) {
        // 从目标日期的下一天开始便利
        int x = i, r = i;
        for (int j = 0; j < 4; j++) {
            x = x * 10 + r % 10;
            r /= 10;
        }
        if (check(x) && (x != date) && (x >= date)) {
            cout << x << "\n";
            break;
        }
    }

    for (int i = date / 10000; i < 10000; i++) {
        int a = i / 1000;
        int b = i % 1000 / 100;
        int c = i % 100 / 10;
        int d = i % 10;

        if (a == c && b == d && a != b) {
            // 控制年份满足ABAB型
            int x = i, r = i;
            for (int j = 0; j < 4; j++) {
                x = x * 10 + r % 10;
                r /= 10;
            }
            if (check(x) && (x != date) && (x >= date)) {
                cout << x << "\n";
                break;
            }
        }


    }

    return 0;
}




3.NOIP2016 普及组 回文日期

题目描述

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用 8 位数字表示一个日期,其中,前 4 位代表年份,接下来 2 位代表月份,最后 2 位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的 8 位数字是回文的。现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。

一个 8 位数字是回文的,当且仅当对于所有的 i(1 <= i <= 8)从左向右数的第 i 个数字和第 9-i 个数字(即从右向左数的第 i 个数字)是相同的。

例如:

  • 对于 2016 年 11 月 19 日,用 8 位数字 20161119 表示,它不是回文的。
  • 对于 2010 年 1 月 2 日,用 8 位数字 20100102 表示,它是回文的。
  • 对于 2010 年 10 月 2 日,用 8 位数字 20101002 表示,它不是回文的。

每一年中都有 12 个月份:

其中,1, 3, 5, 7, 8, 10, 12 月每个月有 31 天;4, 6, 9, 11 月每个月有 30 天;而对于 2 月,闰年时有 29 天,平年时有 28 天。

一个年份是闰年当且仅当它满足下列两种情况其中的一种:

  1. 这个年份是 4 的整数倍,但不是 100 的整数倍;
  2. 这个年份是 400 的整数倍。

例如:

  • 以下几个年份都是闰年:2000, 2012, 2016。
  • 以下几个年份是平年:1900, 2011, 2014。

输入格式

两行,每行包括一个 8 位数字。

第一行表示牛牛指定的起始日期。

第二行表示牛牛指定的终止日期。

保证 date1 和 date2 都是真实存在的日期,且年份部分一定为 4 位数字,且首位数字不为 0。

保证 date1 一定不晚于 date2 。

输出格式

一个整数,表示在 date1 和 date2 之间,有多少个日期是回文的。

样例1

样例输入1

20110101
20111231

样例输出1

1

样例2

样例输入2

20000101
20101231

样例输出2

2

提示

【样例说明】

对于样例 1,符合条件的日期是 20111102。

对于样例 2,符合条件的日期是 20011002 和 20100102。

【子任务】

对于 60% 的数据,满足 date1 = date2。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
​
using namespace std;
​
int months[13] = {
        0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
​
int is_leap(int y) {
    if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
        return 1;
    }
    return 0;
}
​
bool check(int date) {
    int year = date / 10000;
    int month = date % 10000 / 100;
    int day = date % 100;
​
    if (month <= 0 || month >= 13) {
        return false;
    }
​
    if (month != 2 && day > months[month]) {
        return false;
    }
​
    if (month == 2) {
        if (day > months[2] + is_leap(year)) {
            return false;
        }
    }
​
    return true;
}
​
int main() {
    int date1, date2;
    cin >> date1 >> date2;
​
    int res = 0;
    for (int i = 0; i < 10000; i++) {
        int x = i, r = i;
        for (int j = 0; j < 4; j++) {
            x = x * 10 + r % 10;
            r /= 10;
        }
        if (x >= date1 && x <= date2 && check(x)) {
            res++;
        }
    }
​
    cout << res << "\n";
​
​
    return 0;
}




4.日期计算

题目描述

给定一个年份 y 和一个整数 d,问这一年的第 d 天是几月几日?

注意闰年的 2 月有 29 天。

满足下面条件之一的是闰年:

  1. 年份是 4 的整数倍,而且不是 100 的整数倍;
  2. 年份是 400 的整数倍。

输入格式

输入的第一行包含一个整数 y,表示年份,年份在 1900 到 2015 之间(包含 1900 和 2015)。

输入的第二行包含一个整数 d,d 在 1 至 365 之间。

输出格式

输出两行,每行一个整数,分别表示答案的月份和日期。

数据范围

1900 ≤ y ≤ 2015,

1 ≤ d ≤ 365

输入样例1

2015
80

输出样例1

3
21

输入样例2

2000
40

输出样例2

2
9

代码

#include<iostream>
#include<cstring>
#include<algorithm>
​
using namespace std;
​
int temp = 1;
int months[13] = {
        0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
​
int is_leap(int y) {
    if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
        return 1;
    }
    return 0;
}
​
int main() {
    int year, day;
    cin >> year >> day;
​
    while (day > months[temp]) {
        if (temp == 2) {
            day -= months[temp] + is_leap(year);
        } else {
            day -= months[temp];
        };
​
​
        temp++;
    }
    if(day == 0) {
        if(temp - 1 == 2) {
            cout << temp - 1 << "\n" << months[temp - 1] + is_leap(year) << "\n";
        }
        else {
            cout << temp - 1 << "\n" << months[temp - 1] << "\n";
        }
        
    }
    else {
        cout << temp << "\n" << day << "\n";
    }
​
​
    return 0;
}




5.日期差值

有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。

输入格式

输入包含多组测试数据。

每组数据占两行,分别表示两个日期,形式为 YYYYMMDD

输出格式

每组数据输出一行,即日期差值。

数据范围

年份范围[1, 9999] , 保证输入日期合法,测试数据的组数不超过 100。

输入样例

20110412
20110422

输出样例

11

代码

#include<iostream>
#include<cstring>
#include<algorithm>
​
using namespace std;
​
const int months[] = {
        0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
​
int is_leapyear(int x) {
    if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0)) {
        return 1;
    }
    return 0;
}
​
int getdays(int y, int m) {
    if (m == 2) {
        return months[2] + is_leapyear(y);
    }
    return months[m];
}
​
int calc(int year, int month, int day) {
    int res = 0;
​
    for (int i = 1; i < year; i++) {
        res += 365 + is_leapyear(i);
    }
​
    for (int i = 1; i < month; i++) {
        res += getdays(year, i);
    }
    res += day;
​
    return res;
}
​
int main() {
    int y1, y2, m1, m2, d1, d2;
    while (~scanf("%4d%2d%2d\n%4d%2d%2d", &y1, &m1, &d1, &y2, &m2, &d2)) {
        printf("%d\n", 1 + abs(calc(y1, m1, d1) - calc(y2, m2, d2)));
    }
​
​
    return 0;
}

如果有其它日期问题的相关题目,也可以分享到评论区owo~