「题解」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年。
最后,在确定这个日期是平年或是闰年,分别算出月和日。
代码(看到最后有惊喜)
#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控制台信息):
# ===== 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
>>>