Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
1464 字
7 分钟
AD 2020

题目描述#

统计 起始日期(Y1M1D1)到结束日期(Y2M2D2)之间(包含首尾) 的「减灾日」总数,需考虑闰年对日期有效性的影响

关键定义#

减灾日判定规则#

  • 日期格式统一为 YYYYMMDD(8 位数字字符串,例如 2111 年 2 月 2 日表示为 21110202)
  • 若该 8 位字符串中包含子串 “202”,则该日期为减灾日

闰年判定规则#

  • 符合以下任一条件即为闰年:
    • 能被 400 整除
    • 能被 4 整除但不能被 100 整除
bool Year(int x) {
if ((x % 4 == 0 && x % 100 != 0) || x % 400 == 0) return true;
return false;
}
  • 闰年 2 月有 29 天,平年 2 月有 28 天
    • 用于判断日期合法性、计算天数
    • 题目已保证输入日期有效,无需额外验证输入,但计算过程中需考虑

输入输出要求#

输入#

  • 第一行是正整数 T(1 ≤ T ≤ 10⁵),表示测试用例数量
  • 每组用例一行,包含 6 个整数:Y1 M1 D1 Y2 M2 D2
    • Y1 M1 D1:起始年 / 月 / 日
    • Y2 M2 D2:结束年 / 月 / 日
  • 数据约束:
    • 起始日期 ≤ 结束日期
    • 日期范围在 20000101 ~ 99991231 之间
    • 所有日期均为有效日期
  • 注意:输入输出数据量较大,需使用快速 IO 方法(如 C++ 的 scanf/printf)

输出#

  • 每组用例输出一行一个整数,即该日期区间内的减灾日总数

关键补充(从样例提炼)#

若某一年的年份(YYYY)本身包含 “202”(如 2202 年,YYYY=2202),则该年的所有日期都是减灾日,无需逐个判断日期的月和日。

示例说明#

输入示例#

3
2111 02 01 2111 02 03
2202 01 01 2202 12 31
2000 01 01 9999 12 31

输出示例#

1
365
44294

解题思路#

  1. 关键观察
  • 观察到数据范围在 20000101 ~ 99991231 之间,若是每个组数据都爆力查找,一定会超时,需要考虑更高效的算法,利用前缀和优化查询效率,答案就是 结束日期 - 开始日期 (若开始日期也是则 + 1)。
  1. 算法设计
    • 将数组 f 定义为 f[i][j][k] 表示从 20000101 到 i 年 j 月 k 日 之间的减灾日数量。
    • 直接暴力检查 “ijk” 是否为灾难日,并用 val 来线性存储,若是,则 val = val + 1, 且f[i][j][k] = val(避免了通过状态转移的方式解决问题,更加简便)
    • 整体时间复杂度为O(T)
  2. 本题收获/踩坑点
    • 在年月日转换为字符串时,忘记了前导零
    • 自己写的toString函数时,忘记了处理前导零的情况(对前导零的处理并不擅长)
//这是我目前想到的处理前导零的方法
// x 表示处理的值 mod 表示最高位的基数(比如 4444 最高位基数为 1000)
string to_string(int x,int mod){
string s = "";
while(mod >= 1){ //表示当前剩余位数
s = s + char((x - x % mod) / mod + '0'); // 最高位 = x - 除了最高位以外的数字
x %= mod; //去除最高位
mod /= 10; //位数 - 1
}
return x;
}
  • 我在处理闰年的数据非常冗余,判断当前是否是闰年并且是2月份,可以直接在年份中修改2月的天数为29天(若不是闰年则为28天)
//直接在年份中修改2月的天数为29天(若不是闰年则为28天)
if( y % 400 == 0 || (y % 100 != 0 && y % 4 == 0) ) months[2] = 29;
else months[2] = 28;

代码#

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define x first
#define y second
#define endl "\n"
typedef signed long long LL;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int a[10000][15][33];
int m[13] = { 0, 31, 28, 31, 30 ,31, 30, 31, 31, 30, 31, 30 ,31 };
bool Year(int x) {
if ((x % 4 == 0 && x % 100 != 0) || x % 400 == 0) {
return true;
}
return false;
}
//分别表示 当前值 和 预期位数(4位是 1000, 3位 100 以此类推)
string to_string(int x,int mod) {
string s = "";
while (mod >= 1) {
s = s + char((x - x % mod) / mod + 48);
x = x % mod;
mod = mod / 10;
}
return s;
}
int check(string s) {
for (int i = 0; i <= 5; i++) {
if (s[i] == '2' && s[i + 1] == '0' && s[i + 2] == '2') {
return 1;
}
}
return 0;
}
//推荐写法
// void init( )
// {
//     int total = 0;
//     for( int y = 2000; y <= 9999; ++ y )
//     {
//         if( y % 400 == 0 || (y % 100 != 0 && y % 4 == 0) ) months[2] = 29;
//         else months[2] = 28;
//         for( int m = 1; m <= 12; ++ m )
//         {
//             for( int d = 1; d <= months[m]; ++ d )
//             {
//                 if( check( y, m, d ) ) total ++;
//                 sum[y][m][d] = total;
//             }
//         }
//     }
// }
//不推荐写法:第一次写
void init() {
for (int i = 2000; i <= 9999; i++) { //从 2000 年到 9999年
a[i][0][0] = a[i - 1][12][31]; // i 年 0 月 0 日从 i - 1 年 12 月 31 日转换来
for (int j = 1; j <= 12; j++) {
int flag = int(Year(i) && j == 2); //如果当前为 闰年 且 2月份
a[i][j][0] = a[i][j - 1][m[j - 1] + int(Year(i) && (j - 1) == 2)];
for (int k = 1; k <= m[j] + flag; k++) {
string s = to_string(i, 1000) + to_string(j,10) + to_string(k,10);
a[i][j][k] = a[i][j][k - 1] + check(s); //若是减灾日则 + 1否则迭代
}
}
}
}
void solve() {
string s;
int y1, y2, m1, m2, d1, d2;
cin >> y1 >> m1 >> d1 >> y2 >> m2 >> d2;
//s = to_string(y1, 1000) + to_string(m1, 10) + to_string(d1 + 1, 10);
// cout << s << endl;
// cout << check(s) << endl;
cout << a[y2][m2][d2] - a[y1][m1][d1 - 1] << endl;
}
signed main() {
IOS;
init();
int _;
cin >> _;
while (_--) {
solve();
}
}
AD 2020
https://blog.rookiesama.space/posts/题解/ad-2020/
作者
Rookiesama
发布于
2026-01-19
许可协议
CC BY

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00