【AcWing】蓝桥杯集训每日一题Day8|日期问题|前缀和|3498.日期差值(C++)

3498.日期差值
3498. 日期差值 - AcWing题库
难度:简单
时/空限制:1s / 64MB
总通过数:5763
总尝试数:18345
来源:上海交通大学考研机试题
算法标签模拟日期问题

题目内容

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

输入格式

输入包含多组测试数据。
每组数据占两行,分别表示两个日期,形式为 YYYYMMDD

输出格式

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

数据范围

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

输入样例:
20110412
20110422
输出样例:
11
题目解析
  1. 因为如果两个日期是连续的,规定之间的天数是两天,也就是头尾都要算
  2. 有多组测试数据,最多不超过100组
  3. 每个测试数据输入两个日期,谁在前谁在后不一定,计算一下两个日期之间的天数
问两个数之间的天数的话,有一个常用的技巧,类似于前缀和

可以算一下公元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的天数

![[Pasted image 20240330172014.png]]

这样只用实现一个函数就可以,这个函数计算一下从第一天到某一天经过的天数

  • 因为它头尾都要算,所以查算完之后要加一个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)

做日期问题,模板写法

  1. 先定一下每个月的天数
  2. 写一个函数,判断某一年是不是闰年
  3. 写一个辅助函数,用来判断某一个月的天数
#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;
}
  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值