3498.日期差值
3498. 日期差值 - AcWing题库 |
---|
难度:简单 |
时/空限制:1s / 64MB |
总通过数:5763 |
总尝试数:18345 |
来源:上海交通大学考研机试题 |
算法标签模拟日期问题 |
题目内容
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
输入格式
输入包含多组测试数据。
每组数据占两行,分别表示两个日期,形式为 YYYYMMDD
。
输出格式
每组数据输出一行,即日期差值。
数据范围
年份范围 [1, 9999]
保证输入日期合法。
测试数据的组数不超过 100。
输入样例:
20110412
20110422
输出样例:
11
题目解析
- 因为如果两个日期是连续的,规定之间的天数是两天,也就是头尾都要算
- 有多组测试数据,最多不超过100组
- 每个测试数据输入两个日期,谁在前谁在后不一定,计算一下两个日期之间的天数
问两个数之间的天数的话,有一个常用的技巧,类似于前缀和
可以算一下公元1年1月1日到给定这个日期 D 2 D_{2} D2,经过的天数
再算一下到 D 1 D_{1} D1天经过的天数,
只要做一个减法,用1到 D 2 D_{2} D2的天数减去1到 D 1 D_{1} D1的天数,中间剩下的就是 D 1 D_{1} D1到 D 2 D_{2} D2的天数
这样只用实现一个函数就可以,这个函数计算一下从第一天到某一天经过的天数
- 因为它头尾都要算,所以查算完之后要加一个1
这个技巧可以把一个区间问题,从两边都可以变,变成一端固定,只动另外一端的问题,可以少处理一半的边界
考虑一下怎样计算从第一天到某一天的天数
从第一天到y年m月d日的天数
先看数据范围
年份是1到10000之间,一共有100组数据
如果按天来枚举的话,1万年,就是365万天,一共有100组数据,最坏情况下需要算3.65亿次,不一定不能过,因为这个题常数比较小,但是有超时的风险
如何优化
如果按年来枚举,先统计一下前y-1年的天数,这样只需要大概枚举10000次,前y-1年很好枚举,一年一年枚举,平年就加365,闰年就加366
枚举完之后再看第y年,可以枚举一下第y年的前m-1月,最多枚举12次,算一下第y年某一月的天数累加起来
最后再算第y年m月的天数,就是d
这样每一个数据的计算量就是1万多次,一共100个数据,时间复杂度就是 O ( 1000000 ) O(1000000) O(1000000)
做日期问题,模板写法
- 先定一下每个月的天数
- 写一个函数,判断某一年是不是闰年
- 写一个辅助函数,用来判断某一个月的天数
#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_leap(int year)
{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
return 1;
return 0;
}
int get_days(int y, int m)
{
if (m == 2)
return 28 + is_leap(y);
return months[m];
}
//怎么计算从第一天到某个日期的天数
int calc(int y, int m, int d)
{
int res = 0;
//先计算前y-1年的天数
for (int i = 1; i < y; i ++)
{
res += 365 + is_leap(i);
}
//再计算第y年前m-1个月的天数
for (int i = 1; i < m; i ++)
{
res += get_days(y, i);
}
return res + d;
}
int main()
{
//定义一下两个日期
int y1, m1, d1, y2, m2, d2;
//使用格式化读入方式
while (~scanf("%04d%02d%02d\n%04d%02d%02d", &y1, &m1, &d1, &y2, &m2, &d2))
printf("%d\n", abs(calc(y1, m1, d1) - calc(y2, m2, d2)) + 1);
return 0;
}