大家可以在洛谷提交:
题目描述【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 行,每行一个非负整数 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。
测试点编号Q =Q=r_i \leri?≤1110001000365365221000100010^4104331000100010^51054410000100003\times 10^53×1055510000100002.5\times 10^62.5×1066610^51052.5\times 10^62.5×1067710^51055\times 10^65×1068810^510510^71079910^510510^9109101010^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表示是否为闰年4if(p)t[2]=29; 5for(int i=1;i<=12;i++) 6if(n>=t[i])n-=t[i],m++; 7else{ 8d+=n,t[2]=28;//将t[2]复原9return;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+366int 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 { 3int d=1,m=1,y=1; 4n-=1721424; 5y+=n/1461*4,n%=1461;//四年四年跳6//1095=3*365 7if(n<1095){ 8//平年 9y+=n/365,n%=365;10work(d,m,n); 11} 12else{13//闰年14n-=1095,y+=3;15work(d,m,n,1);16}17cout<<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 { 3int d=15,m=10,y=1582;//跳到1582.10.154n-=2299161; 5if(n<=77){ 6//答案在1582年中 7if(n<=16)cout<<d+n<<" "<<m<<" "<<y<<endl; 8else if(n<=46)cout<<n-16<<" "<<m+1<<" "<<y<<endl; 9elsecout<<n-46<<" "<<m+2<<" "<<y<<endl;10return; 11}12n-=78,d=1,m=1,y=1583;//跳到1583.1.113//146097=303*365+97*366//四百年中有97个闰年14y+=n/146097*400,n%=146097;//四百年四百年跳 15/*16以下的年份从383开始,1583%400=383 ==> 不是闰年,则从383~39917、400、1~382三段进行跳(只剩下最后四百年没跳了) 18*/19if(n<6209){20//6209=13*365+4*366(383~399)21y+=n/1461*4,n%=1461;//四年四年跳22if(n<365)work(d,m,n);23elseif(n<731){24n-=365,y++;25work(d,m,n,1);26}27else{28n-=731,y+=2;29y+=n/365,n%=365;30work(d,m,n); 31}32cout<<d<<" "<<m<<" "<<y<<endl;33}34else{35if(n<6575){36//6575=13*65+5*366,即0年 37n-=6209,d=1,m=1,y+=17;38work(d,m,n,1);39cout<<d<<" "<<m<<" "<<y<<endl;40}41else{42//1~38243n-=6575,d=1,m=1,y+=18;44y+=n/36524*100,n%=36524;45//36524=76*365+24*366//一百年一百年跳46if(n<36159){47//36159=75*365+24*366(前99年) 48y+=n/1461*4,n%=1461;49if(n<1095){50y+=n/365,n%=365;51work(d,m,n);52}53else{54n-=1095,y+=3;55work(d,m,n,1);56}57}58else{59//最后100年60n-=36159,y+=99;61work(d,m,n);//不是闰年 62}63cout<<d<<" "<<m<<" "<<y<<endl; 64}65}66 }总代码:
1 #include<bits/stdc++.h>2 using namespace std;3 #define int long long4 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表示是否为闰年10if(p)t[2]=29; 11for(int i=1;i<=12;i++) 12if(n>=t[i])n-=t[i],m++; 13else{ 14d+=n,t[2]=28;//将t[2]复原15return; 16} 17 } 18 void solve1(){ 19//1461=3*365+366 20int d=1,m=1,y=-4713; 21y+=n/1461*4,n%=1461; 22if(n<366)work(d,m,n,1);//剩余n天,小于366为闰年23else{ 24n-=366,y++; 25y+=n/365,n%=365;//加为平年26work(d,m,n); 27}//y已经跳正确 。28cout<<d<<" "<<m<<" "<<-y<<" BC"<<endl; 29 } 30 void solve2() 31 { 32int d=1,m=1,y=1; 33n-=1721424; 34y+=n/1461*4,n%=1461;//四年四年跳35//1095=3*365 36if(n<1095){ 37//平年 38y+=n/365,n%=365; 39work(d,m,n);40}41else{ 42//闰年 43n-=1095,y+=3; 44work(d,m,n,1); 45} 46cout<<d<<" "<<m<<" "<<y<<endl; 47 } 48 void solve3() 49 { 50int d=15,m=10,y=1582;//跳到1582.10.1551n-=2299161; 52if(n<=77){ 53//答案在1582年中 54if(n<=16)cout<<d+n<<" "<<m<<" "<<y<<endl; 55else if(n<=46)cout<<n-16<<" "<<m+1<<" "<<y<<endl; 56elsecout<<n-46<<" "<<m+2<<" "<<y<<endl; 57return;58} 59n-=78,d=1,m=1,y=1583;//跳到1583.1.1 60//146097=303*365+97*366//四百年中有97个闰年 61y+=n/146097*400,n%=146097;//四百年四百年跳62/* 63以下的年份从383开始,1583%400=383 ==> 不是闰年,则从383~399 64、400、1~382三段进行跳(只剩下最后四百年没跳了)65*/ 66if(n<6209){ 67//6209=13*365+4*366(383~399) 68y+=n/1461*4,n%=1461;//四年四年跳 69if(n<365)work(d,m,n); 70elseif(n<731){ 71n-=365,y++; 72work(d,m,n,1); 73} 74else{ 75n-=731,y+=2; 76y+=n/365,n%=365; 77work(d,m,n);78} 79cout<<d<<" "<<m<<" "<<y<<endl; 80} 81else{ 82if(n<6575){ 83//6575=13*65+5*366,即0年84n-=6209,d=1,m=1,y+=17; 85work(d,m,n,1); 86cout<<d<<" "<<m<<" "<<y<<endl; 87} 88else{ 89//1~382 90n-=6575,d=1,m=1,y+=18; 91y+=n/36524*100,n%=36524; 92//36524=76*365+24*366//一百年一百年跳 93if(n<36159){ 94//36159=75*365+24*366(前99年)95y+=n/1461*4,n%=1461; 96if(n<1095){ 97y+=n/365,n%=365; 98work(d,m,n); 99}100else{101n-=1095,y+=3;102work(d,m,n,1);103}104}105else{106//最后100年107n-=36159,y+=99;108work(d,m,n);//不是闰年 109}110cout<<d<<" "<<m<<" "<<y<<endl; 111}112}113 }114 signed main()115 {116//freopen("julian.in","r",stdin);117//freopen("julian.out","w",stdout);118cin>>q;119for(int i=1;i<=q;i++)120{121cin>>r;122n=r;123if(n<=1721423)solve1();124if(r>1721423&&r<=2299160) solve2();125if(r>2299160)solve3();126}127return 0;128 }以上来源于SCDN的weixin_45429627+个人理解 。
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
