蓝桥杯103 日期问题

题目链接:https://www.lanqiao.cn/problems/103/learning/

前置知识

输入解析

要会什么?

会用这一句把 AA/BB/CC 读进来:

cpp 复制代码
int a,b,c;
scanf("%d/%d/%d", &a, &b, &c);

要记住什么?

"%d/%d/%d" 的意思是:

先读一个整数,接着必须遇到 / ,再读一个整数,再遇到 / ,再读一个整数

题目格式固定,所以不用担心空格、换行、乱格式

读进来的 a,b,c 都是 0~99 的两位数(比如 02 会读成整数 2)

两位年份到四位年份映射

要会什么?

把两位数的 yy 变成四位数年份:

cpp 复制代码
int fullYear(int yy) { 
    return (yy <= 59) ? (2000 + yy) : (1900 + yy);
}

要记住什么?

题目限定最终年份只能在 1960~2059,所以映射只能是:

00~59 → 2000~2059

60~99 → 1960~1999

条件运算符 ?: 的读法:

条件 ? A : B

条件成立返回 A,否则返回 B

闰年判断

要会什么?

写一个函数判断 y 是否为闰年:

cpp 复制代码
bool isLeap(int y) {
    return (y % 400 == 0) || (y % 4 == 0 && y % 100 != 0);
}

要记住什么?

能被 400 整除是闰年

能被 4 整除且不能被 100 整除也是闰年

其他是平年

运算符优先级:&& 比 || 高,但写括号最稳

月份天数表 + 日期合法性判断

要会什么?

用数组存每月天数,并写 valid(y,m,d) 判断是否合法:

cpp 复制代码
static int md[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};

bool valid(int y, int m, int d) {
    if (y < 1960 || y > 2059) return false;
    if (m < 1 || m > 12) return false;
    int days = md[m] + (m == 2 && isLeap(y)); // 闰年2月+1
    return d >= 1 && d <= days;
}

要记住什么?

md0=0 只是占位,让月份 1~12 直接当下标好用。

days = mdm + (m==2 && isLeap(y))

这里 (m==2 && isLeap(y)) 结果是 true/false,在 C/C++ 里会当 1/0 用。

三种日期格式枚举思想

要会什么?

输入 a/b/c 可能代表三种解释方式,所以只需要枚举这三种:

yy/mm/dd → (fullYear(a), b, c)

mm/dd/yy → (fullYear(c), a, b)

dd/mm/yy → (fullYear(c), b, a)

要记住什么?

这题不是"枚举所有天",而是"枚举所有解释方式",最多 3 个候选,极快。

每个候选都用 valid() 筛一下,合法的才收集。

排序 + 去重

要会什么

把收集到的候选日期排序,然后去掉重复项:

sort(ans.begin(), ans.end());

ans.erase(unique(ans.begin(), ans.end()), ans.end());

要记住什么

不用死记位置,知道 unique 会标记重复区起点,erase 删掉这个起点后的所有元素就够了。

容器与数据结构表达

要会什么?

用一个能自动按年-月-日排序的结构存答案:

vector<pair<int, pair<int,int>>> ans; // (y, (m, d))

插入时可以这样:

ans.push_back({y, {m, d}});

要记住什么?

pair 默认比较规则是字典序:

先比 first(年)

年相同再比 second.first(月)

月相同再比 second.second(日)

所以你 sort(ans.begin(), ans.end()) 就会自动按年月日排好

格式化输出

要会什么?

输出成 yyyy-mm-dd,月日补 0:

printf("%d-%02d-%02d\n", y, m, d);

要记住什么?

%02d:宽度 2,不够左侧补 0

3 会输出成 03

完整代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int fullYear(int yy) { // 00-59 -> 2000-2059, 60-99 -> 1960-1999
    return (yy <= 59) ? (2000 + yy) : (1900 + yy);
}

bool isLeap(int y) {
    return (y % 400 == 0) || (y % 4 == 0 && y % 100 != 0);
}

bool valid(int y, int m, int d) {
    if (y < 1960 || y > 2059) return false;
    if (m < 1 || m > 12) return false;
    static int md[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int days = md[m] + (m == 2 && isLeap(y));
    return d >= 1 && d <= days;
}

int main() {
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);

    vector<pair<int, pair<int,int> > > ans; // (y, (m, d))

    int y1 = fullYear(a), m1 = b, d1 = c;   // yy/mm/dd
    int y2 = fullYear(c), m2 = a, d2 = b;   // mm/dd/yy
    int y3 = fullYear(c), m3 = b, d3 = a;   // dd/mm/yy

    if (valid(y1,m1,d1)) ans.push_back(make_pair(y1, make_pair(m1,d1)));
    if (valid(y2,m2,d2)) ans.push_back(make_pair(y2, make_pair(m2,d2)));
    if (valid(y3,m3,d3)) ans.push_back(make_pair(y3, make_pair(m3,d3)));

    sort(ans.begin(), ans.end());
    ans.erase(unique(ans.begin(), ans.end()), ans.end());

    for (int i = 0; i < ans.size(); ++i) {
        int y = ans[i].first;
        int m = ans[i].second.first;
        int d = ans[i].second.second;
        printf("%d-%02d-%02d\n", y, m, d);
    }
    return 0;
}
相关推荐
lingran__14 小时前
C++ STL map 与 set 底层剖析与模拟实现万字详解|基于红黑树,复刻 SGI-STL 泛型复用架构
开发语言·c++·stl·set·map·泛型编程·sgi-stl
星轨初途14 小时前
LeetCode 热题 100——day11 滑动窗口最大值
数据结构·c++·算法·leetcode·职场和发展
重生之小比特14 小时前
【初阶C++】内存管理
c++·内容运营
不会代码的小猴1 天前
21. 泛型编程上
开发语言·c++·笔记·算法
青瓦梦滋1 天前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
一只旭宝1 天前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
Lhan.zzZ1 天前
在 Visual Studio 2022 中打造可扩展的动态链接库模块:从零搭建到原理解析
开发语言·c++·visual studio
zh路西法1 天前
【3D SLAM源码解读系列】(二)Small_gicp——5 个积木搭出最优点云配准
c++·pcl·icp·fastgicp·smallgicp·gicp
fpcc1 天前
ubuntu26环境下的开发环境安装处理
c++·并行编程
charlie1145141911 天前
Cinux · 第一次跳进 Ring 3:用户态与特权隔离
开发语言·c++·操作系统·开源项目