回文条件把月日钉死在年份的倒序上:枚举年份、还原月日并校验真实日期,落在区间内则计数。
OJ: roj
题目 ID: 3635
难度:普及-
标签:枚举回文日期与日历python
创建: 2026-10-02 11:56
更新: 2026-10-06 15:33
题目描述
用 8 位数字 YYYYMMDD 表示日期,若这 8 位顺读倒读相同则称回文日期。给定两个真实日期 20110101 / 20111231,输出 1;样例 2 输入 20000101 / 20101231,输出 2。
思路
回文要求 MMDD 等于年份的倒序,因此年份一旦确定,月日就唯一确定。枚举起止年份之间至多 9000 个年份,倒序取出月日,先判月份是否在
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 11:57
# update_at: 2026-10-02 12:04
import sys
MDAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) # 平年每月天数
def solve() -> None:
date1, date2 = map(int, sys.stdin.read().split())
first_year, last_year = date1 // 10000, date2 // 10000 # 起止年份
ans = 0
for year in range(first_year, last_year + 1):
# 关键观察:8 位回文日期的后四位 = 前四位年份的倒序,年份一旦选定,月日就被唯一确定
mmdd = str(year)[::-1]
month, day = int(mmdd[:2]), int(mmdd[2:])
if not 1 <= month <= 12:
continue # 倒序出的月份不在 1~12,该年没有回文日期
days = MDAYS[month - 1]
is_leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) # 题面的闰年规则
if month == 2 and is_leap:
days += 1 # 闰年 2 月 29 天
if not 1 <= day <= days:
continue # 该月没有这一天,构不成真实日期
date = year * 10000 + month * 100 + day # 拼回 8 位日期
ans += date1 <= date <= date2 # 只有首尾年份可能越出区间
print(ans)
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 15:32
* update_at: 2026-10-06 15:32
*/
#include <cstdio>
using namespace std;
typedef long long ll;
int mdays[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 平年每月天数,下标即月份
// 闰年判定:4 的倍数且不是 100 的倍数,或 400 的倍数
bool is_leap(ll year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
int main() {
ll date1, date2; // 起止日期(8 位整数)
ll first_year, last_year;
ll year;
ll ans = 0;
scanf("%lld %lld", &date1, &date2);
first_year = date1 / 10000; // 起始年份
last_year = date2 / 10000; // 终止年份
for (year = first_year; year <= last_year; year++) {
// 回文要求后 4 位 = 年份倒序,于是年份一确定,月日就唯一确定
ll a = year / 1000; // 年份千位
ll b = year / 100 % 10; // 年份百位
ll c = year / 10 % 10; // 年份十位
ll d = year % 10; // 年份个位
ll month = d * 10 + c; // 倒序后的前两位作月份
ll day = b * 10 + a; // 倒序后的后两位作日期
if (month < 1 || month > 12) {
continue; // 倒序出的月份不合法,该年没有回文日期
}
ll days = mdays[month]; // 本月天数
if (month == 2 && is_leap(year)) {
days = 29;
}
if (day < 1 || day > days) {
continue; // 该月没有这一天
}
ll date = year * 10000 + month * 100 + day; // 拼回 8 位日期
if (date1 <= date && date <= date2) { // 只有首尾年份可能越出区间
ans++;
}
}
printf("%lld\n", ans);
return 0;
}