日期&&时差&&星期问题(蓝桥杯)

目录

1、常见时间、日期类问题思路

2、核心模板 ——判断日期是否合法

3、日期问题&&回文日期

4、日期差值、星期几

5、航班时间


1、常见时间、日期类问题思路

  • 日期问题、回文日期——(题目给定两个时间点,让找到之间满足条件的日期有多少个)

     思路:用一个循环直接枚举,先判断是否是正常的日期,再判断是否满足条件。

  • 日期差值、星期几——(题目给定两个日期,让我们求中间相差多少天)

      思路:用数学计算出每个日期距离0001年01月01日有多少天,然后相减即可。

  • 航班时间——(给定两个飞机的起飞时间和抵达时间,求在天上飞了多少时间。**各地区存在时差**)

      思路:经过化简时差可以约掉((t1-时差)-(t2-时差))/2=(t1+t2)/2,最后转化成秒进行相加再/2就行了。

  • 有坑有大坑!!!在后台的隐藏数据,两个日期可能是颠倒的,并不一定是前面是小日期,后面是大日期。如果题目上没有明确给出第一个日期小,第二个日期大,那就必定有坑,就需要我们用max判断一下,再进行计算。

2、核心模板 ——判断日期是否合法

int check(int year, int month, int day)//判断是否为合法的日期
{
	if (month == 0 || month > 12) return 0;
	if (day == 0) return 0;
	if (month != 2)
	{
		if (day > days[month]) return 0;
	}
	if(month==2)
	{
		int lsp = year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
		if (day > 28 + lsp) return 0;
	}
	return 1;
}

3、日期问题&&回文日期

题目描述——日期问题

小明正在整理一批历史文献。这些历史文献中出现了很多日期。

小明知道这些日期都在1960年1月1日至2059年12月31日。

令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。

更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入格式
一个日期,格式是”AA/BB/CC”。

即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。

输出格式
输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。

多个日期按从早到晚排列。

数据范围
0≤A,B,C≤9


输入样例:
 

02/03/04


输出样例:
 

2002-03-04
2004-02-03
2004-03-02
#include<iostream>//日期问题
#include<algorithm>

using namespace std;

int a, b, c;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

int check(int year, int month, int day)
{
	if (month == 0 || month > 12) return 0;
	if (day == 0) return 0;
	if (month != 2)
	{
		if (day > days[month]) return 0;
	}
	if(month==2)
	{
		int lsp = year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
		if (day > 28 + lsp) return 0;
	}
	return 1;
}

int main()
{
	scanf("%d/%d/%d", &a, &b, &c);//巧妙借用scanf的输入格式
	for (int i = 19600101; i <= 20591231; i++)
	{
		int year = i / 10000;
		int month = i % 10000 / 100;
		int day = i % 100;
		if (check(year, month, day))
		{
			if (year%100 == a && month == b && day == c     //年月日
			|| year%100 == c && month == a && day == b      //月日年
			|| year%100 == c && month == b && day == a)     //日月年
			{
				printf("%d-%02d-%02d\n", year, month, day);
			}
		}
	}
	return 0;
}

题目描述——回文日期

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用 8 位数字表示一个日期,其中,前 4 位代表年份,接下来 2 位代表月份,最后 2 位代表日期。

显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的 8 位数字是回文的。

现在,牛牛想知道:在他指定的两个日期之间(包含这两个日期本身),有多少个真实存在的日期是回文的。

一个 8 位数字是回文的,当且仅当对于所有的 i(1≤i≤8) 从左向右数的第 i 个数字和第 9−i 个数字(即从右向左数的第 i 个数字)是相同的。

例如:

对于 2016 年 11 月 19 日,用 8 位数字 20161119 表示,它不是回文的。
对于 2010 年 1 月 2 日,用 8 位数字 20100102 表示,它是回文的。
对于 2010 年 10 月 2 日,用 8 位数字 20101002 表示,它不是回文的。


输入格式
输入包括两行,每行包括一个 8 位数字。

第一行表示牛牛指定的起始日期 date1,第二行表示牛牛指定的终止日期 date2。保证 date1 和 date2 都是真实存在的日期,且年份部分一定为 4 位数字,且首位数字不为 0。

保证 date1 一定不晚于 date2。

输出格式
输出共一行,包含一个整数,表示在 date1 和 date2 之间,有多少个日期是回文的。

输入样例:
 

20110101
20111231


输出样例:
 

1
#include<iostream>//回文日期
#include<algorithm>

using namespace std;

int x, y, ans;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

int check(int year, int month, int day)
{
	if (month == 0 || month > 12) return 0;
	if (day == 0) return 0;
	if (month != 2)
	{
		if (day > days[month]) return 0;
	}
	if (month == 2)
	{
		int lsp = year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
		if (day > 28 + lsp) return 0;
	}
	return 1;
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
	cin >> x >> y;
	for (int i = x; i <= y; i++)
	{
		int year = i / 10000;
		int month = i % 10000 / 100;
		int day = i % 100;
		if (check(year, month, day))
		{
			if (year / 1000 == day % 10 && year / 100 % 10 == day / 10 && year / 10 % 10 == month % 10 && year % 10 == month / 10)
			{
				ans++;
			}
		}
	}
	cout << ans << endl;
	return 0;
}

4、日期差值、星期几

题目描述——日期差值

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

输入格式
输入包含多组测试数据。

每组数据占两行,分别表示两个日期,形式为 YYYYMMDD。

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

数据范围
年份范围 [1,9999],
保证输入日期合法。

输入样例:
 

20110412
20110422


输出样例:
 

11
#include<iostream>//一直有个别数据相差1,给我整emo了......
#include<algorithm>//最后发现虽然考虑闰年了,但考虑的条件少了一部分!!!啊啊啊啊啊

using namespace std;

int n, m;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

int cal(int n)
{
	int ans=0;
	int year = n / 10000;
	int month = n % 10000 / 100;
	int day = n % 100;
	for (int i = 1; i < year; i++)
	{
		if (i % 400 == 0 || i % 4 == 0 && i % 100 != 0) ans++;
	}
	ans += (year - 1) * 365;
	for (int i = 1; i < month; i++)
	{
		ans += days[i];
	}
	if(year%400==0&&month>2||year%4==0&&year%100!=0&&month>2) ans++;//*********就错在这
	ans += day;
	return ans;
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
	while (cin >> n >> m)
	{
		if (n < m) swap(n, m);
		cout << cal(n) - cal(m) + 1 << endl;
	}
	return 0;
}

题目描述——星期几

已知 1 年 1 月 1 日是星期一。现在给定一个日期,请你判断是星期几。

注意闰年的 2 月有 29 天。

满足下面条件之一的是闰年:

  • 年份是 4 的整数倍,而且不是 100 的整数倍;
  • 年份是 400 的整数倍。

输入格式
输入包含多组测试数据。

每组数据占一行,包含一个整数 d 表示日,一个字符串 m 表示月,一个整数 y 表示年。

月份 1∼12,依次如下所示:

January, February, March, April, May, June, July, August, September, October, November, December


输出格式
每组数据输出一行结果,输出一个字符串表示给定日期是星期几。

周一至周日依次如下所示:

Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday


数据范围
1000≤y≤3000,
给定日期保证合法。
每个输入最多包含 100 组数据。

输入样例:
 

9 October 2001
14 October 2001


输出样例:
 

Tuesday
Sunday
#include<iostream>//星期几
#include<algorithm>

using namespace std;
typedef long long LL;

LL sum;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
string weeks[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
string months[13] = { "0","January","February","March","April","May","June","July","August","September","October","November","December" };

int main()
{
	LL n, m, x;
	string str;
	ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
	while (cin >> m >> str >> n)
	{
		int year = n;
		int month;
		int day = m;
		for (int i = 1; i <= 12; i++)
		{
			if (str == months[i]) month = i;
		}
		sum = (year - 1) * 365;//求(year-1)年有多少天
		for (int i = 1; i < year; i++)
		{
			if (i % 400 == 0 || i % 4 == 0 && i % 100 != 0) sum++;//求(year-1)年有多少闰年
		}
		for (int i = 1; i < month; i++)
		{
			sum += days[i];//求year年有多少天
		}
		sum += day;
		if (year % 400 == 0 && month > 2 || year % 4 == 0 && year % 100 != 0 && month > 2)
		{
			sum++;//判断year年是否是闰年
		}
		cout << weeks[sum % 7] << endl;
	}
	return 0;
}

5、航班时间

题目描述——航班时间

小 h 前往美国参加了蓝桥杯国际赛。

小 h 的女朋友发现小 h 上午十点出发,上午十二点到达美国,于是感叹到“现在飞机飞得真快,两小时就能到美国了”。小 h 对超音速飞行感到十分恐惧。

仔细观察后发现飞机的起降时间都是当地时间。

由于北京和美国东部有 12 小时时差,故飞机总共需要 14 小时的飞行时间。

不久后小 h 的女朋友去中东交换。小 h 并不知道中东与北京的时差。

但是小 h 得到了女朋友来回航班的起降时间。小 h 想知道女朋友的航班飞行时间是多少。

对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。

输入格式
一个输入包含多组数据。

输入第一行为一个正整数 T,表示输入数据组数。

每组数据包含两行,第一行为去程的起降时间,第二行为回程的起降时间。

起降时间的格式如下:

h1:m1:s1 h2:m2:s2
h1:m1:s1 h3:m3:s3 (+1)
h1:m1:s1 h4:m4:s4 (+2)
第一种格式表示该航班在当地时间h1时m1分s1秒起飞,在当地时间当日h2时m2分s2秒降落。

第二种格式表示该航班在当地时间h1时m1分s1秒起飞,在当地时间次日h2时m2分s2秒降落。

第三种格式表示该航班在当地时间h1时m1分s1秒起飞,在当地时间第三日h2时m2分s2秒降落。

输出格式
对于每一组数据输出一行一个时间hh:mm:ss,表示飞行时间为hh小时mm分ss秒。

注意,当时间为一位数时,要补齐前导零,如三小时四分五秒应写为03:04:05。

数据范围
保证输入时间合法(0≤h≤23,0≤m,s≤59),飞行时间不超过24小时。

输入样例:

3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)


输出样例:
 

04:09:05
12:10:39
14:22:05

//去乘起飞时间+航行时间+时差=去乘降落时间  (公式一)
//回程起飞时间+航行时间-时差=回程降落时间  (公式二)
//根据公式一+公式二:
//去乘起飞时间+回程起飞时间+2*航行时间=去乘降落时间+回程降落时间
//航行时间=(去乘降落时间-去乘起飞时间+回程降落时间-回程起飞时间)/2

#include<iostream>//航班时差
#include<algorithm>

using namespace std;

int get_time()
{
	int h1, h2, m1, m2, s1, s2, d = 0, sum;
	scanf("%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);
	sum = (d * 24 * 3600 + h2 * 3600 + m2 * 60 + s2) - (h1 * 3600 + m1 * 60 + s1);
	return sum;
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int t1 = get_time();
		int t2 = get_time();
		int t = (t1 + t2) / 2;
		printf("%02d:%02d:%02d\n", t / 3600, t / 60 % 60, t % 60);
	}
	return 0;
}

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大小胖虎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值