蓝桥杯日期问题合集

[蓝桥杯2015初赛]星系炸弹

题目描述

在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。
每个炸弹都可以设定多少天之后爆炸。
比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。
有一个贝塔炸弹,a年b月c日放置,定时为n天,请你计算它爆炸的准确日期。

输入

输入存在多组数据,每组数据输入一行,每一行输入四个正整数a,b,c,n
输入保证日期在1000-01-01到2020-01-01之间,且日期合法。
n不超过1000

输出

请填写该日期,格式为 yyyy-mm-dd 即4位年份2位月份2位日期。比如:2015-02-19
请严格按照格式书写。不能出现其它文字或符号。

样例输入

2015 1 1 15
2014 11 9 1000

分析

先单位统一,将初始的日期化为天数,然后加上流逝的天数,再将该天数化为日期。注意闰年的特判。(公元元年为 公元 1 年)

# include <iostream>

int month[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool run(int num) {
	return (num % 4 == 0 && num % 100 !=0) || num % 400 == 0;
}

int main() {
	int y1;
	int m1;
	int d1;
	int pa;
	
	while (std::cin >> y1 >> m1 >> d1 >> pa) {
		int s = 0;
		
		for (int i=1; i<y1; i++) {
			if (run(i)) {
				s += 366;
			} else {
				s += 365;
			}
		}
		
		if (run(y1)) {
			month[2] = 29;
		} else {
			month[2] = 28;
		}
		
		for (int i=0; i<m1; i++) {
			s += month[i];
		}
		
		s += d1 + pa;
		
		int y2;
		int m2;
		int d2;
		
		for (y2=1; ; y2++) {
			if (run(y2)) {
				if (s <= 366) {
					break;
				} else {
					s -= 366;
				}
			} else {
				if (s <= 365) {
					break;
				} else {
					s -= 365;
				}
			}
		} 
					
		if (run(y2)) {
			month[2] = 29;	
		} else {
			month[2] = 28;
		}	
		
		for (m2=1; ; m2++) {
			if (s <= month[m2]) {
				d2 = s;
				break;
			} else {
				s -= month[m2];
			}
		}
		
		std::cout << y2 << '-';
		
		if (m2 / 10 == 0) {
			std::cout << '0';
		}
		
		std::cout << m2 << "-";
		
		if (d2 / 10 == 0) {
			std::cout << '0';
		}
		
		std::cout << d2 << "\n";
	}
	
	return 0;
}

[蓝桥杯2017初赛]日期问题

题目描述

小明正在整理一批历史文献。这些历史文献中出现了很多日期。
小明知道这些日期都在1960年1月1日至2059年12月31日。
令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入

一个日期,格式是"AA/BB/CC"。 (0 <= A, B, C <= 9)

输出

输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。
多个日期按从早到晚排列。

样例输入

02/03/04

样例输出

2002-03-04
2004-02-03
2004-03-02

分析

日期有 年/月/日月/日/年日/月/年 这三种方式,其中年份可能是20世纪,也可能是21世纪,因此共6种情况。先排序、去重,再判断每一种日期是否合理,合理则按照题目要求输出。

# include <iostream>
# include <vector>
# include <algorithm>

struct date {
	int year;
	int month;
	int day;
	
	bool operator < (date rhs) {
		if (year < rhs.year) {
			return true;
		} else if (year == rhs.year) {
			if (month < rhs.month) {
				return true;
			} else if (month == rhs.month) {
				return day < rhs.day;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	bool operator == (date rhs) {
		return year == rhs.year && month == rhs.month && day == rhs.day;
	}
};

bool run(int num) {
	return (num % 4 ==0 && num % 100 != 0) || num % 400 == 0;
}

bool is(date t) {
	if (t.year < 1960 || t.year > 2059) {
		return false;
	}
	
	int mon[14] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

	if (run(t.year)) {
		mon[2] = 29;
	}
	
	if (t.month > 12 || t.month < 1) {
		return false;
	}
	
	if (t.day <= mon[t.month] && t.day > 0) {
		return true;
	} else {
		return false;
	}
}

int main() {
	int a, b, c;
	char ct;
	std::cin >> a >> ct >> b >> ct >> c;	
	
	std::vector<date> d;
	d.resize(6);
	
	d[0].year = 2000 + a;
	d[0].month = b;
	d[0].day = c;
	
	d[1].year = 2000 + c;
	d[1].month = a;
	d[1].day= b;
	
	d[2].year = 2000 + c;
	d[2].month = b;
	d[2].day= a;
	
	d[3].year = 1900 + a;
	d[3].month = b;
	d[3].day = c;
	
	d[4].year = 1900 + c;
	d[4].month = a;
	d[4].day= b;
	
	d[5].year = 1900 + c;
	d[5].month = b;
	d[5].day= a;
	
	std::sort(d.begin(), d.end());
	d.erase(std::unique(d.begin(), d.end()), d.end());
	
	for (int i=0; i<d.size(); i++) {
		if (is(d[i])) {
			std::cout << d[i].year << "-";
			
			if (0 == d[i].month / 10) {
				std::cout << 0;
			}
			
			std::cout << d[i].month << "-";
			
			if (0 == d[i].day / 10) {
				std::cout << 0;
			}
			
			std::cout << d[i].day << "\n";
		}
	}
	
	return 0;
}

[蓝桥杯2018初赛]星期一

题目描述

整个20世纪(1901年1月1日至2000年12月31日之间),一共有多少个星期一?
(不要告诉我你不知道今天是星期几)

输出

输出一个整数表示答案

分析

如果从现在的时间倒着推回 公元1月1日 , 那结果是星期一, 但是有些手机上面的日历是星期六 。由于1582年时日历对春分的记载和地球公转到春分点的实际时间相差十天,1582年10月4日为星期四,1582年10月15日为星期五,中间的10天被删除。进行推算时将公元1月1日“看成”星期一即可。

我们先来按照此思路验证一下 2020 年 3 月 29 日 是星期几

# include <iostream>

bool run(int num) {
	return (num % 4 == 0 && num % 100 != 0) || num % 400 == 0;
}

int main() {
	int s2 = 0;
	
	for (int i=1; i<2020; i++) {
		if (run(i)) {
			s2 += 366;
		} else {
			s2 += 365;
		}
	}
	
	s2 += 31 + 29 + 29;
	
	std::cout << s2 % 7;
	
	return 0;
}

输出结果为 0, 代表星期日。

AC代码

# include <iostream>

bool run(int num) {
	return (num % 4 == 0 && num % 100 != 0) || num % 400 == 0;
}

int main() {
	int y2 = 2000;
	int m2 = 12;
	int d2 = 31;
	
	int s2 = 0;
	
	for (int i=1; i<=y2; i++) {
		if (run(i)) {
			s2 += 366;
		} else {
			s2 += 365;
		}
	}

	int y1 = 1901;
	int m1 = 1;
	int d1 = 1;
	
	int s1 = 0;
	
	for (int i=1; i<y1; i++) {
		if (run(i)) {
			s1 += 366;
		} else {
			s1 += 365;
		}
	}
	
	s1 += 1;
	
	int cnt = 0;
	for (int i=s1; i<=s2; i++) {
		if (i % 7 == 1) {
			++cnt;
		}
	}
	
	std::cout << cnt;
	
	return 0;
}

在数论中,计算日期还有 基姆拉尔森计算公式蔡勒公式 ,在此不做展开。 (其实是懒得学)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值