【正经题解】儒略日
2024-02-20 16:53:42
发布于:浙江
14阅读
0回复
0点赞
题意分析
给出距离 4713.1.1 B.C 的天数,要求计算出具体的日期
思路分析
显然,模拟即可。考虑根据历法的分为不同的阶段进行计算,然后从大周期到小周期进行处理。
可以将最特殊的 1582 年单独分为一段,它之前的分为一段,它之后的分为一段。
对于第一段(1581-),最大的周期即为四年(四年一闰),因此以四年为周期划分;对于每个四年周期内,以一年为周期划分;对于每个一年周期内,以一月为周期划分;然后处理天数即可。由于 4713 B.C 刚好为闰年,因此从头开始划分即可。注意公元前和公元后的判断。
对于第二段(1582),按月划分,特判 10 月的 10 天缺失即可。
对于第三段(1583+),最大的周期为四百年(世纪年四次一闰),接下来为一百年,然后为四年、一年、一月,依次划分即可。因为最开始不满一个周期,因此可以接着划分成 1583 , 1584-1599 ,1600+ 三段,第一段按一年的最大周期处理,第二段按四年的最大周期处理,第三段按四百年的最大周期处理即可。注意世纪年的特殊闰年处理。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
static int f;static char c;
for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>void write(T x){
static int q[64];int cnt=0;
if(x==0)return pc('0'),void();
if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10,x/=10;
while(cnt--)pc(q[cnt]+'0');
}
const int data0[13]={0,31,28,31,30,31,30,31,31,30,31,30,31},//平年
data1[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年
void getyear(void){//这个是用来获取平年一年天数的,也就是 365 天
int tmp=0;
for(int i=1;i<=12;++i)
tmp+=data0[i];
printf("year:%d\n",tmp);
}
void getsum(void){
int sum=0;
for(int i=4713;i>=1;--i)
sum+=365+(i%4==1);
//reach 1.1.1
printf("reach 1.1.1:%d\n",sum);
for(int i=1;i<=1581;++i)
sum+=365+(i%4==0);
//reach 1582.1.1
for(int i=1;i<=9;++i)
sum+=data0[i];
//reach 1582.10.1
sum+=4;
//reach 1582.10.5 1582.10.15
printf("reach 1582.10.15:%d\n",sum);
sum+=17;
//reach 1582.11.1
for(int i=11;i<=12;++i)
sum+=data0[i];
//reach 1583.1.1
printf("reach 1583.1.1:%d\n",sum);
}
const int R0=1721424,R1=2299161,R2=2299239;
long long getyear0(long long r){
// r 表示从公元前 4713 年 1 月 1 日开始还需要经过多少天
long long L=0,R=4712;
while(L<R){
long long M=(L+R+1)>>1;
long long D=(M+3)/4+M*365;
if(D>r)R=M-1;else L=M;
}
return L;
}
long long getyear1(long long r){
// r 表示从公元 1 年 1 月 1 日开始还需要经过多少天
long long L=0,R=1581;
while(L<R){
long long M=(L+R+1)>>1;
long long D=M/4+M*365;
if(D>r)R=M-1;else L=M;
}
return L;
}
long long getyear2(long long r){
// r 表示从公元 1583 年 1 月 1 日开始还需要经过多少天
long long L=0,R=1000000000;
while(L<R){
long long M=(L+R+1)>>1;
long long D=(M+2)/4-(M+82)/100+(M+382)/400+M*365;
if(D>r)R=M-1;else L=M;
}
return L;
}
void work(void){
int q;read(q);
while(q--){
long long r;read(r);
if(r<R0){
//before 1.1.1
long long Y=getyear0(r);
r-=(Y+3)/4+Y*365;++r;
//这里 ++r 是因为此时已经是 1 月 1 日了,而后面 r 还需要用来计算天数,所以 r 初始就是 1
Y=4713-Y;long long M=1;
// Y 是年份, M 是月份
if(Y%4!=1){//平年
while(r>data0[M])
r-=data0[M],++M;
}
else{//闰年
while(r>data1[M])
r-=data1[M],++M;
}
write(r),pc(' '),write(M),pc(' '),write(Y),pc(' ');
pc('B'),pc('C');
}
else if(r>=R0&&r<R1){
//before 1582.10.5 1582.10.15
r-=R0;
long long Y=getyear1(r);
r-=Y/4+Y*365;++r;
//这里 ++r 是因为此时已经是 1 月 1 日了,而后面 r 还需要用来计算天数,所以 r 初始就是 1
Y=Y+1;long long M=1;
// Y 是年份, M 是月份
if(Y%4!=0){//平年
while(r>data0[M])
r-=data0[M],++M;
}
else{//闰年
while(r>data1[M])
r-=data1[M],++M;
}
write(r),pc(' '),write(M),pc(' '),write(Y);
}
else if(r>=R1&&r<R2){
//before 1583.1.1
r-=R1;
if(r<17){
r+=15;//从 10 月 15 日开始算起
write(r),pc(' '),write(10),pc(' '),write(1582);
}
else{
r-=17;++r;
//这里 ++r 是因为此时已经是 1582 年 11 月 1 日了,而后面 r 还需要用来计算天数,所以 r 初始就是 1
long long M=11;
// M 是月份
while(r>data0[M])
r-=data0[M],++M;
write(r),pc(' '),write(M),pc(' '),write(1582);
}
}
else if(r>=R2){
r-=R2;
long long Y=getyear2(r);
r-=(Y+2)/4-(Y+82)/100+(Y+382)/400+Y*365;++r;
//这里 ++r 是因为此时已经是 1583 年 1 月 1 日了,而后面 r 还需要用来计算天数,所以 r 初始就是 1
Y+=1583;long long M=1;
// Y 是年份, M 是月份
if(Y%4!=0||(Y%100==0&&Y%400!=0)){
while(r>data0[M])
r-=data0[M],++M;
}
else{
while(r>data1[M])
r-=data1[M],++M;
}
write(r),pc(' '),write(M),pc(' '),write(Y);
}
pc('\n');
}
}
int main(){
// getsum();
work();
return 0;
}
这里空空如也
有帮助,赞一个