CSP2020-儒略历
大家可以在洛谷提交:
题目描述
为了简便计算,天文学家们使用儒略日(Julian day)来表达时间。所谓儒略日,其定义为从公元前 4713 年 1 月 1 日正午 12 点到此后某一时刻间所经过的天数,不满一天者用小数表达。若利用这一天文学历法,则每一个时刻都将被均匀的映射到数轴上,从而得以很方便的计算它们的差值。
现在,给定一个不含小数部分的儒略日,请你帮忙计算出该儒略日(一定是某一天的中午 12 点)所对应的公历日期。
我们现行的公历为格里高利历(Gregorian calendar),它是在公元 1582 年由教皇格里高利十三世在原有的儒略历(Julian calendar)的基础上修改得到的(注:儒略历与儒略日并无直接关系)。具体而言,现行的公历日期按照以下规则计算:
- 公元 1582 年 10 月 15 日(含)以后:适用格里高利历,每年一月 3131 天、 二月 2828 天或 2929 天、三月 3131 天、四月 3030 天、五月 3131 天、六月 3030 天、七月 3131 天、八月 3131 天、九月 3030 天、十月 3131 天、十一月 3030 天、十二月 3131 天。其中,闰年的二月为 2929 天,平年为 2828 天。当年份是 400400 的倍数,或日期年份是 44 的倍数但不是 100100 的倍数时,该年为闰年。
- 公元 1582 年 10 月 5 日(含)至 10 月 14 日(含):不存在,这些日期被删除,该年 10 月 4 日之后为 10 月 15 日。
- 公元 1582 年 10 月 4 日(含)以前:适用儒略历,每月天数与格里高利历相同,但只要年份是 44 的倍数就是闰年。
- 尽管儒略历于公元前 45 年才开始实行,且初期经过若干次调整,但今天人类习惯于按照儒略历最终的规则反推一切 1582 年 10 月 4 日之前的时间。注意,公元零年并不存在,即公元前 1 年的下一年是公元 1 年。因此公元前 1 年、前 5 年、前 9 年、前 13 年……以此类推的年份应视为闰年。
输入格式
第一行一个整数 QQ,表示询问的组数。
接下来 QQ 行,每行一个非负整数 r_iri,表示一个儒略日。
输出格式
对于每一个儒略日 r_iri,输出一行表示日期的字符串 s_isi。共计 QQ 行。 s_isi 的格式如下:
- 若年份为公元后,输出格式为
Day Month Year
。其中日(Day)、月(Month)、年(Year)均不含前导零,中间用一个空格隔开。例如:公元 2020 年 11 月 7 日正午 12 点,输出为7 11 2020
。 - 若年份为公元前,输出格式为
Day Month Year BC
。其中年(Year)输出该年份的数值,其余与公元后相同。例如:公元前 841 年 2 月 1 日正午 12 点,输出为1 2 841 BC
。
输入输出样例
3
10
100
1000
11 1 4713 BC
10 4 4713 BC
27 9 4711 BC
3
2000000
3000000
4000000
14 9 763
15 8 3501
12 7 6239
见附件中的 julian/julian3.in
见附件中的 julian/julian3.ans
说明/提示
【数据范围】
测试点编号 | Q =Q= | r_i \leri≤ |
---|---|---|
11 | 10001000 | 365365 |
22 | 10001000 | 10^4104 |
33 | 10001000 | 10^5105 |
44 | 1000010000 | 3\times 10^53×105 |
55 | 1000010000 | 2.5\times 10^62.5×106 |
66 | 10^5105 | 2.5\times 10^62.5×106 |
77 | 10^5105 | 5\times 10^65×106 |
88 | 10^5105 | 10^7107 |
99 | 10^5105 | 10^9109 |
1010 | 10^5105 | 年份答案不超过 10^9109 |
附件下载:https://www.luogu.com.cn/fe/api/problem/downloadAttachment/4h186sh9
模拟思想,通过分类讨论:
(1)-4713年到-1年;(n<=1721423)
(2)1年到1582年10月4日;(n>1721423&&n<=2299160)
(3)1582年10月15日;(n>2299160)
通过三个函数进行操作(跨年)+(跨月+跨日)
主要操作为年份。其中work函数将最后不足一年的天数和月数进行操作。
代码实现如下:
1 void work(int &d,int &m,int &n,int p=0){
2 //从1.1往后跳n天并存在d与m中
3 //p=1/0表示是否为闰年
4 if(p) t[2]=29;
5 for(int i=1;i<=12;i++)
6 if(n>=t[i]) n-=t[i],m++;
7 else{
8 d+=n,t[2]=28;//将t[2]复原
9 return;
10 }
11 }
1 int t[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
其中t数组存储每个月的天数。
SOLVE1:
每四年为一闰年,则四年四年跳,当跳到只剩下不足四年时,就对n进行判断:
1:不足一年,则为闰年,p=1,work();
2:超过一年,则一年一年跳,注意都不是闰年,到最后再work()。
void solve1(){
//1461=3*365+366
int d=1,m=1,y=-4713;
y+=n/1461*4,n%=1461;
if(n<366) work(d,m,n,1);//剩余n天,小于366为闰年
else{
n-=366,y++;
y+=n/365,n%=365;//加为平年
work(d,m,n);
}//y已经跳正确。
cout<<d<<" "<<m<<" "<<-y<<" BC"<<endl;
}
SOLVE2:
因为跳的天数大于公元前1年,则先减去公元前的天数再减去公元1年的第一天(),因为d(day)已经设为1.然后就四年四年跳,同上。(注意从这开始当n不足4年时,前三年为平年,最后一年为闰年)
1 void solve2()
2 {
3 int d=1,m=1,y=1;
4 n-=1721424;
5 y+=n/1461*4,n%=1461;//四年四年跳
6 //1095=3*365
7 if(n<1095){
8 //平年
9 y+=n/365,n%=365;
10 work(d,m,n);
11 }
12 else{
13 //闰年
14 n-=1095,y+=3;
15 work(d,m,n,1);
16 }
17 cout<<d<<" "<<m<<" "<<y<<endl;
18 }
SOLVE3:
从这开始就细节起来了,因为跳到了1582年10月15日,n-2299161;
第一种:答案就在1582年里,就直接讨论剩下的三个月。
第二种:超过1582年,就先跳到1583.1.1,然后开始四百年四百年的跳。
跳到了不足四百年时又进行讨论(注意到闰年的判断条件变了)
1583年内%400==383,到四百四百跳完之后,到了不知道多少--83年时,则在(新的四百年)383到399年间、400年间、1到382年间讨论。
383到399先四年四年跳,在对剩下不足四年进行操作。(注意前两年会遇到闰年,后两年为平年。
400年为闰年,直接操作。
1到382年先100年一百年跳,再四年四年跳。
1 void solve3()
2 {
3 int d=15,m=10,y=1582;//跳到1582.10.15
4 n-=2299161;
5 if(n<=77){
6 //答案在1582年中
7 if(n<=16)cout<<d+n<<" "<<m<<" "<<y<<endl;
8 else if(n<=46) cout<<n-16<<" "<<m+1<<" "<<y<<endl;
9 else cout<<n-46<<" "<<m+2<<" "<<y<<endl;
10 return;
11 }
12 n-=78,d=1,m=1,y=1583;//跳到1583.1.1
13 //146097=303*365+97*366//四百年中有97个闰年
14 y+=n/146097*400,n%=146097;//四百年四百年跳
15 /*
16 以下的年份从383开始,1583%400=383 ==> 不是闰年,则从383~399
17 、400、1~382三段进行跳(只剩下最后四百年没跳了)
18 */
19 if(n<6209){
20 //6209=13*365+4*366(383~399)
21 y+=n/1461*4,n%=1461;//四年四年跳
22 if(n<365) work(d,m,n);
23 else if(n<731){
24 n-=365,y++;
25 work(d,m,n,1);
26 }
27 else{
28 n-=731,y+=2;
29 y+=n/365,n%=365;
30 work(d,m,n);
31 }
32 cout<<d<<" "<<m<<" "<<y<<endl;
33 }
34 else{
35 if(n<6575){
36 //6575=13*65+5*366,即0年
37 n-=6209,d=1,m=1,y+=17;
38 work(d,m,n,1);
39 cout<<d<<" "<<m<<" "<<y<<endl;
40 }
41 else{
42 //1~382
43 n-=6575,d=1,m=1,y+=18;
44 y+=n/36524*100,n%=36524;
45 //36524=76*365+24*366//一百年一百年跳
46 if(n<36159){
47 //36159=75*365+24*366(前99年)
48 y+=n/1461*4,n%=1461;
49 if(n<1095){
50 y+=n/365,n%=365;
51 work(d,m,n);
52 }
53 else{
54 n-=1095,y+=3;
55 work(d,m,n,1);
56 }
57 }
58 else{
59 //最后100年
60 n-=36159,y+=99;
61 work(d,m,n);//不是闰年
62 }
63 cout<<d<<" "<<m<<" "<<y<<endl;
64 }
65 }
66 }
总代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define int long long
4 int q,r;
5 int n;
6 int t[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
7 void work(int &d,int &m,int &n,int p=0){
8 //从1.1往后跳n天并存在d与m中
9 //p=1/0表示是否为闰年
10 if(p) t[2]=29;
11 for(int i=1;i<=12;i++)
12 if(n>=t[i]) n-=t[i],m++;
13 else{
14 d+=n,t[2]=28;//将t[2]复原
15 return;
16 }
17 }
18 void solve1(){
19 //1461=3*365+366
20 int d=1,m=1,y=-4713;
21 y+=n/1461*4,n%=1461;
22 if(n<366) work(d,m,n,1);//剩余n天,小于366为闰年
23 else{
24 n-=366,y++;
25 y+=n/365,n%=365;//加为平年
26 work(d,m,n);
27 }//y已经跳正确。
28 cout<<d<<" "<<m<<" "<<-y<<" BC"<<endl;
29 }
30 void solve2()
31 {
32 int d=1,m=1,y=1;
33 n-=1721424;
34 y+=n/1461*4,n%=1461;//四年四年跳
35 //1095=3*365
36 if(n<1095){
37 //平年
38 y+=n/365,n%=365;
39 work(d,m,n);
40 }
41 else{
42 //闰年
43 n-=1095,y+=3;
44 work(d,m,n,1);
45 }
46 cout<<d<<" "<<m<<" "<<y<<endl;
47 }
48 void solve3()
49 {
50 int d=15,m=10,y=1582;//跳到1582.10.15
51 n-=2299161;
52 if(n<=77){
53 //答案在1582年中
54 if(n<=16)cout<<d+n<<" "<<m<<" "<<y<<endl;
55 else if(n<=46) cout<<n-16<<" "<<m+1<<" "<<y<<endl;
56 else cout<<n-46<<" "<<m+2<<" "<<y<<endl;
57 return;
58 }
59 n-=78,d=1,m=1,y=1583;//跳到1583.1.1
60 //146097=303*365+97*366//四百年中有97个闰年
61 y+=n/146097*400,n%=146097;//四百年四百年跳
62 /*
63 以下的年份从383开始,1583%400=383 ==> 不是闰年,则从383~399
64 、400、1~382三段进行跳(只剩下最后四百年没跳了)
65 */
66 if(n<6209){
67 //6209=13*365+4*366(383~399)
68 y+=n/1461*4,n%=1461;//四年四年跳
69 if(n<365) work(d,m,n);
70 else if(n<731){
71 n-=365,y++;
72 work(d,m,n,1);
73 }
74 else{
75 n-=731,y+=2;
76 y+=n/365,n%=365;
77 work(d,m,n);
78 }
79 cout<<d<<" "<<m<<" "<<y<<endl;
80 }
81 else{
82 if(n<6575){
83 //6575=13*65+5*366,即0年
84 n-=6209,d=1,m=1,y+=17;
85 work(d,m,n,1);
86 cout<<d<<" "<<m<<" "<<y<<endl;
87 }
88 else{
89 //1~382
90 n-=6575,d=1,m=1,y+=18;
91 y+=n/36524*100,n%=36524;
92 //36524=76*365+24*366//一百年一百年跳
93 if(n<36159){
94 //36159=75*365+24*366(前99年)
95 y+=n/1461*4,n%=1461;
96 if(n<1095){
97 y+=n/365,n%=365;
98 work(d,m,n);
99 }
100 else{
101 n-=1095,y+=3;
102 work(d,m,n,1);
103 }
104 }
105 else{
106 //最后100年
107 n-=36159,y+=99;
108 work(d,m,n);//不是闰年
109 }
110 cout<<d<<" "<<m<<" "<<y<<endl;
111 }
112 }
113 }
114 signed main()
115 {
116 //freopen("julian.in","r",stdin);
117 //freopen("julian.out","w",stdout);
118 cin>>q;
119 for(int i=1;i<=q;i++)
120 {
121 cin>>r;
122 n=r;
123 if(n<=1721423) solve1();
124 if(r>1721423&&r<=2299160) solve2();
125 if(r>2299160) solve3();
126 }
127 return 0;
128 }
以上来源于SCDN的weixin_45429627+个人理解。
感谢各位来到我的博客园。
CSP2020-儒略历的更多相关文章
- CSP2020复赛游记
CSP2020复赛游记 由于本蒟蒻侥幸通过PJ和TG的分数线并且侥幸的拿了一等,所以侥幸的来参加复赛 11.04~11.05 期中考,挂 11.06 对答案,炸 11.07 开始了第一次CSP复赛 坐 ...
- CSP-2020 退役记
CSP-2020 游记 第2次参加CSP-- Day -5~-7 每天笔试+机试 Day -8~-9 在家放松(写作业) Day 0 鸡鸭月考 Day 1 9:30以前 愉快的在别人月考的时候离开鸡鸭 ...
- 【游记】CSp2020
同步发表于洛谷博客 初赛 Day -2 做了个模拟(非洛谷),只有一丁点分,显然过不了 (盗张 i am ak f 的图) Day 0 颓,颓,颓,又做了一套模拟,坚定了退役的信心. Day 1 人好 ...
- CSP2020游记
初赛 这次考试完全没准备好啊-- Day0 (10.10) 本来打算看看初赛的内容 然后因为各种原因咕了-- 就做了一下洛谷的模拟卷 结果 \(40 \text{min}\) 得 \(80 \text ...
- CSP2020 游记
Day -28 后天就初赛了,考了一套模拟题,自闭,心态爆炸,感觉退役不远了 Day -26(初赛) 香农是谁??? 手写随机nth_element与O(n)的哈希表??? 阅读程序T2时间复杂度分析 ...
- CSP2020 自爆记
Day -1 - 2020.11.5 发现自己 dp 学得很烂--刷了几道 dp 找找感觉. 晚上死活睡不着,觉得要爆炸了. Day 0 - 2020.11.6 白天在学校觉得人飘了. 傍晚回来拿了准 ...
- python笔记7:日期和时间
Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示. 时间 ...
- Python 学习笔记(6)--常用模块(2)
一.下载安装 下载安装有两种方式: yum\pip\apt-get 或者源码 下载源码 解压源码 进入目录 编译源码 python setup.py build 安装源码 python setup.p ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- 20145205 《Java程序设计》第7周学习总结
教材学习内容总结 认识时间与日期 1.格林威治时间(GMT):通过观察太阳而得,因为地球公转轨道为椭圆形且速度不一,本身自传减速而造成误差. 2.世界时(UT):通过观测远方星体跨过子午线而得,受地球 ...
随机推荐
- Linux下Nodejs安装(完整详细)转
Linux下安装有两种方式,一个是下载源码make编译安装. 另外一种是比较推荐的,直接下载编译好的二进制,官方比较推荐后者. //Linux 64bit version wget --no-chec ...
- LR录制附件上传后,回放报错
使用LR录制附件上传后,点击回放,发现报错:没有找到上传的文件 Could not obtain information about submitted file "C:\Users\Adm ...
- 彻底关闭Windows自动更新
win+r--输入services.msc(服务管理窗口)停止windows update服务并禁用同时在恢复里,改为无操作 win + r --输入gpedit.msc(本地组策略编辑器)家庭版没有 ...
- Rabbit 高级操作
Rabbit 高级操作 1.过期时间TTL 过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取:过了时间之后消息将自动被删除. RabbitMQ可以对消息和队列设置TTL. ...
- AT2567-[ARC074C]RGB Sequence【dp】
正题 题目链接:https://www.luogu.com.cn/problem/AT2567 题目大意 长度为\(n\)的包含三种颜色\(RGB\)的序列,\(m\)个限制\([l,r,k]\)表示 ...
- Stream聚合函数
Stream班介绍 幼稚园开学的第一天,各们家长把小朋友送到了园里,各位小朋友都你看看我,我看看你.有的嚎啕大哭,有的呆若木鸡....这里时候园长安排我拿来小本本记录入园的小朋友.... 记录小朋友 ...
- 关于mysql基础
早就想把自己的数据库基础巩固一下,然而一直没有时间,今天终于抽出时间对mysql数据库基础进行了学习与扩展. mysql与其他数据库的区别 Sqlite: 开源免费,体积小,单文件,没有进程.磁盘读性 ...
- virtualbox 桥接模式网络配置虚拟机之间通讯以及虚拟机联网
一般来说桥接模式可以解决所有的网络问题 网卡选择 [root@HELLO network-scripts]# cat ifcfg-eth0 TYPE="Ethernet" PROX ...
- spring-data-redis 上百万的 QPS 压力太大连接失败,我 TM 人傻了
大家好,我们最近业务量暴涨,导致我最近一直 TM 人傻了.前几天晚上,发现由于业务压力激增,某个核心微服务新扩容起来的几个实例,在不同程度上,出现了 Redis 连接失败的异常: org.spring ...
- 6.堆和GC
一. 堆和GC介绍 1.java堆的特点 <深入理解java虚拟机>是怎么描述java堆的 Java堆(Java Heap)是java虚拟机所管理的内存中最大的一块 java堆被所有线程共 ...