大佬教程收集整理的这篇文章主要介绍了CSP2020-儒略历,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
大家可以在洛谷提交:
为了简便计算,天文学家们使用儒略日(Julian day)来表达时间。所谓儒略日,其定义为从公元前 4713 年 1 月 1 日正午 12 点到此后某一时刻间所经过的天数,不满一天者用小数表达。若利用这一天文学历法,则每一个时刻都将被均匀的映射到数轴上,从而得以很方便的计算它们的差值。
现在,给定一个不含小数部分的儒略日,请你帮忙计算出该儒略日(一定是某一天的中午 12 点)所对应的公历日期。
我们现行的公历为格里高利历(Gregorian calendar),它是在公元 1582 年由教皇格里高利十三世在原有的儒略历(Julian calendar)的基础上修改得到的(注:儒略历与儒略日并无直接关系)。具体而言,现行的公历日期按照以下规则计算:
第一行一个整数 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
见附件中的 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-儒略历所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。