CSP-S2020 T1 儒略日
題目描述
為了簡便計算,天文學家們使用儒略日(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,表示詢問的組數。
接下來 QQ 行,每行一個非負整數 r_ir**i,表示一個儒略日。
輸出格式
對於每一個儒略日 r_ir**i,輸出一行表示日期的字符串 s_is**i。共計 QQ 行。 s_is**i 的格式如下:
- 若年份為公元后,輸出格式為
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
。
題解:
絕對有能力在考場上調出滿分代碼。
但是掛了60分。
為什么呢?
因為沒審題(微笑)。以為公元后就是按現在的方式計算閏年了,咋調都差12天。其實1582年之后才是按現在的方式計算閏年。
也不知道是審題不行,還是常識沒有。
反正就是SB。掛了60
如果知道是這里的鍋,咋的這100是穩拿的。
就依題意模擬吧。每個人的方法可能都不一樣。我這里的代碼碼了206行。在這里問候一下出題人身體健康。
大體思路就是,先400 400數,再100 100數,再4年4年數,以此優化復雜度。
很多特判。
很多很多特判。
很多很多很多特判。
所有的數都是手算的。(出題人$%&##)
代碼:
#include<cstdio>
#define int long long
using namespace std;
int q,r;
bool flag;
int ping[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int run[]={0,31,29,31,30,31,30,31,31,30,31,30,31};
void solve1()
{
int tot=r/1461;
int year=4713-tot*4;
r-=tot*1461;
if(r>=366)
{
year--;
r-=366;
while(r>=0)
year--,r-=365;
if(r<0)
year++,r+=365;
}
int yue=1;
if((year-1)%4==0)//run
{
while(r-run[yue]>=0)
{
r-=run[yue];
yue++;
}
int ri=r+1;
printf("%lld %lld %lld BC\n",ri,yue,year);
}
else//ping
{
while(r-ping[yue]>=0)
{
r-=ping[yue];
yue++;
}
int ri=r+1;
printf("%lld %lld %lld BC\n",ri,yue,year);
}
}
void solve2()
{
flag=0;
r-=1721424;
if(r<=577736)
{
int tot=r/1461;
int year=1+tot*4;
r-=tot*1461;
tot=r/365;
if(tot==4)
tot--;
year+=tot;
r-=tot*365;
if(year%4==0)
flag=1;
int yue=1;
if(!flag)
{
while(r-ping[yue]>=0)
{
r-=ping[yue];
yue++;
}
}
else
{
while(r-run[yue]>=0)
{
r-=run[yue];
yue++;
}
}
int ri=r+1;
printf("%lld %lld %lld\n",ri,yue,year);
}
else if(r>577736)
{
r+=10;
r-=577736;
if(r<28)
{
printf("%lld 10 1582\n",4+r);
return;
}
else if(r<58)
{
r-=28;
printf("%lld 11 1582\n",1+r);
return;
}
else if(r<89)
{
r-=58;
printf("%lld 12 1582\n",1+r);
return;
}
else if(r<6664)
{
r-=89;
int year=1583;
int last=0;
while(r>=0)
{
if(year%4)
{
r-=365,year++;
last=0;
}
else
{
r-=366,year++;
last=1;
}
}
if(last==1)
r+=366,year--;
else
r+=365,year--;
int yue=1;
if(year%4)
{
while(r-ping[yue]>=0)
{
r-=ping[yue];
yue++;
}
}
else
{
while(r-run[yue]>=0)
{
r-=run[yue];
yue++;
}
}
int ri=1+r;
printf("%lld %lld %lld\n",ri,yue,year);
return;
}
else
{
r-=6664;
int tot=r/146097;
int year=1601+400*tot;
r-=146097*tot;
if(r==146096)
{
printf("31 12 %lld\n",year+399);
return;
}
while(r>=0)
year+=100,r-=36524;
if(r<0)
year-=100,r+=36524;
while(r>=0)
year+=4,r-=1461;
if(r<0)
year-=4,r+=1461;
tot=r/365;
if(tot==4)
tot--;
year+=tot;
r-=tot*365;
if((year%4==0 && year%100)||(year%400==0))
flag=1;
int yue=1;
if(!flag)
{
while(r-ping[yue]>=0)
{
r-=ping[yue];
yue++;
}
}
else
{
while(r-run[yue]>=0)
{
r-=run[yue];
yue++;
}
}
int ri=r+1;
printf("%lld %lld %lld\n",ri,yue,year);
}
}
}
signed main()
{
// freopen("julian.in","r",stdin);
// freopen("julian.out","w",stdout);
scanf("%lld",&q);
while(q--)
{
scanf("%lld",&r);
if(r<1721424)
solve1();
else
solve2();
}
return 0;
}