「題解」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
>>> 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM