0%

「题解」CSP-S 2020 儒略日

谨以此篇题解,纪念我那炸掉的T1。。

基本思路

大模拟,我写了100多行。。

总之就是按照时间依次向后推进

先判断使用哪一历法,当r大于等于2299162时,使用的是格里高利历,反之,使用儒略历。之后分类讨论。

儒略历(r<2299162)

儒略历的话,因为前4713年正好是一个闰年,我就将四年分为了一组,也就是每4年有1461天,算出经过多少年,再算出减去这些年之后还剩的天数(实际上后面都是这个思路)

因为着四年中,第一年就是一个闰年,所以如果剩下的日子小于366,那就按照闰年算出月和日,反之减去366,算出多了多少年,再算日期。

格里高利历(r>=2299162)

真正麻烦的是格里高利历。

格里高利历又多了“百年不闰,四百年再闰”的规则,于是我将400年作为一个周期,每400年97闰,那么每400年就要经过146097天。

总之,为了方便计算,先把r减去2299162。

因为格里高利历开始的时间是1582年的10月15日,如果在这个日期后,但在1582年里,就要分类讨论。而1582年10月15日距离1583年正好77天,这就有了77这个常数。

1583年前

这部分的处理简单粗暴,分成了三类,分别是10月,11月,12月。每类单独算日期。

1583年后(r>77)

我当时想着是直接快进到1600年,因为这一年正好是400的整倍数,可以作为一个周期的起点,但1583年并不是一个闰年,如果不把1600年之前的每4年组合在一起,将会十分难算。于是我打算将1584年作为一个节点。于是我将在1584年之后的日期和在这之前的日期分开计算。

而当时间快进到1584年时,就可以将剩下的16年以4年一组的形式划分,这样算到1600年。

1600年后

当到了1600后,剩下的事情就相对简单了。

首先将每146097年分成一组,这就是一个400年,首先计算出有多少个400年。

然后判断剩下的日子是否属于第一个百年,因为第一个一百年有25个闰年,而剩下的三个百年中,每一百年只有24个闰年,这也是常数36525的由来。

然后将4年确定为一个周期,确定在这100或300年中,这个日期属于哪个4年。

最后,在确定这个日期是平年或是闰年,分别算出月和日。

代码(看到最后有惊喜)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <cstdio>
#include <iostream>

long long q, r, day, month, year;
const int months[15]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monthr[15]={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//const int julian=2297591;
const int julian=2299162;
int Month(), Monthr();

int main(){
freopen("julian.in", "r", stdin);
freopen("julian.out", "w", stdout);

scanf("%lld", &q);
for(int asdf=0; asdf<q; asdf++){
scanf("%lld", &r);
r++;
if(r<julian){
year=(r/1461)*4;
r%=1461;
if(r<=59){
month=r>31?2:1;
day=r>31?r-31:r;
}
else{
if(r<=366){
month=Monthr();
day=r;
}
else{
year+=(r-366)/365+1;
r-=366; r%=365;
month=Month();
day=r;
}
}
if(year<4713)
if(day==0 && month==1)
printf("31 12 %lld BC\n", 4713-year+1);
else
printf("%lld %lld %lld BC\n", day, month, 4713-year);
else
if(day==0 && month==1)
printf("31 12 %lld\n", year-4713);
else
printf("%lld %lld %lld\n", day, month, year-4713+1);
}
else{
r-=julian;
year=1582;
if(r<=77){
if(r<=16){ month=10; day=15+r; }
else if(r<=46){ month=11; day=r-16; }
else { month=12; day=r-46; }
}
else {
r-=77;
if(r<=365){
year++;
month=Month();
day=r;
}
else{
r-=365; year=1584;
if(r<=5844) {
year+=(r/1461)*4;
r%=1461;
if(r<=366){
month=Monthr();
day=r;
}
else {
r-=366; year++;
year+=r/365;
r%=365;
month=Month();
day=r;
}
}
else{
r-=5844; year=1600;
year+=(r/146097)*400;
r%=146097;
if(r<=36525){
year+=(r/1461)*4;
r%=1461;
if(r<=366){ month=Monthr(); day=r; }
else {
r-=366; year++;
year+=r/365; r%=365;
month=Month(); day=r;
}
}
else{
r-=36525; year+=100;
year+=(r/36524)*100;
r%=36524;
if(r<=1460){
year+=r/365;
r%=365;
month=Month();
day=r;
}
else{
r-=1460; year+=4;
year+=(r/1461)*4;
r%=1461;
if(r<=366) { month=Monthr(); day=r; }
else{
r-=366; year++;
year+=r/365;
r%=365;
month=Month();
day=r;
}
}
}
}
}
}
if(day==0 && month==1)
printf("31 12 %lld\n", year-1);
else
printf("%lld %lld %lld\n", day, month, year);
}
// printf("%d %d %d\n", day, month, year);
}

return 0;
}

int Month(){
int i;
for(i=0; i<12; i++){
if(r>months[i]) r-=months[i];
else break;
}
return i+1;
}
int Monthr(){
int i;
for(i=0; i<12; i++){
if(r>monthr[i]) r-=monthr[i];
else break;
}
return i+1;
}
/*
int Month(int x){
if(0<x && x<=31) return 1;
if(31<x && x<=59) return 2;
if(59<x && x<=90) return 3;
if(90<x && x<=120) return 4;
if(120<x && x<=151) return 5;
if(151<x && x<=181) return 6;
if(181<x && x<=212) return 7;
if(212<x && x<=243) return 8;
if(243<x && x<=273) return 9;
if(273<x && x<=304) return 10;
if(304<x && x<=334) return 11;
if(334<x && x<=365) return 12;
if(0<x && x<=31) return 1;
}
int Monthr(int x){
if(0<x && x<=31) return 1;
if(31<x && x<=60) return 2;
if(60<x && x<=91) return 3;
if(91<x && x<=121) return 4;
if(121<x && x<=152) return 5;
if(152<x && x<=182) return 6;
if(182<x && x<=213) return 7;
if(213<x && x<=244) return 8;
if(244<x && x<=274) return 9;
if(274<x && x<=305) return 10;
if(305<x && x<=335) return 11;
if(335<x && x<=366) return 12;
if(0<x && x<=31) return 1;
}*/

最后附上我算这些常数的过程(python控制台信息):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# ===== console log in CSP-S 2020 =====

noilinux@ubuntu:~/Desktop/SX-00019/julian$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:38)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
noilinux@ubuntu:~/Desktop/SX-00019/julian$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:18)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 365*400+97
146097
>>> 4713*365
1720245
>>> 4713*365+1581*365
2297310
>>> 31+28+31+30+31+30+31+31+30+4
277
>>> 4713*365+1581*365+277+(4713%4+1)+(1582%4)
2297591
>>> 365*4+1
1461
>>> 365*3+31+28
1154
>>> 31+28
59
>>> 59+31
90
>>> 17+30+31
78
>>> 3000000-2297591
702409
>>> 702409-(16+30+31)
702332
>>> 4*(702332/1461)
1922.880219028063
>>> 4*(702332//1461)
1920
>>> 702332-4*1461
696488
>>> 702332-4*1920
694652
>>> 702332%1461
1052
>>> 1583+1920
3503
>>> 3501-1582
1919
>>> 3501-1583
1918
>>> 198/4
49.5
>>> 1918/4
479.5
>>> 1918*365+479
700549
>>> 700549+17+30+31
700627
>>> 3000000-700627
2299373
>>> 2299373-(31+28+31+30+31+30+31+15)
2299146
>>> 31+28+31+30+31+30+31+31+30+4+(1582+4713-1)*365
2297587
>>> (1582+4713-1)/4
1573.5
>>> 2297587+1573
2299160
>>> 3000000-2299160
700840
>>> 700840-77
700763
>>> 4*(700763//1461)
1916
>>> 1916*1461
2799276
>>> 700763%1461
944
>>> 700763-365
700398
>>> 700398//1461
479
>>> 4*479
1916
>>> 700398%1461
579
>>> 579-366
213
>>> 1916+1584+1
3501
>>> 365*4+1
1461
>>> 100*365+97
36597
>>> 1600-1584
16
>>> 16*365+4
5844
>>> 365*400+97
146097
>>> 100*365+25
36525
>>> 100*365+24
36524
>>> 365*4
1460
>>>