题解:P7075 [CSP-S2020] 儒略日
TainityAnle · · 题解
这篇题解本来有很多前言,但是说多了都是泪,还是不说了。
题意
给定
简明的题意,屎山的代码。
思路
发现公元 1582 年 10 月 4 日之后改了历法,那么这里就是一个转折点。为了防止出错,我选择将此之前和此之后分开处理,写成 solve1() 和 solve2()。
-
儒略历处理
每
400 年有146100 天。我的做法的流程如下:- 设
N 为经过了多少个整400 年,即取N=\lfloor\frac{n}{146100}\rfloor ,然后使天数n 减去N\times 146100 。 - 取年份
y=-4713+N\times400 。 - 因为公元零年并不存在,所以若
y>1 ,使y 自增1 。 - 因为公元前 4713 年 1 月 1 日被记作第
0 天,我们又是把公元前 4713 年 1 月 1 日当做第1 天数的,所以要把n 加上1 。注意这里不可以一开始就这样做,否则会80 分。 - 处理不足
400 年的整年。这一块可以枚举。从已经得到的y 开始,只要n>366 ,每次判断y 是否是闰年。若是,n 每次减去366 ,否则每次减去365 。每次y 增加1 。 - 处理月。设
month_i 表示i 月有month_i 天。先判断现在得到的年份y 是否为闰年,若是把month_2 设为29 ,否则设为28 。从一月开始,设月份yue=1 ,只要n>month_{yue} ,yue 每次增加1 ,n 减去month_{yue} 。 - 这时我们已经处理好了年和月,剩下的
n 就是日期。但是还有很多细节等待我们处理。让我们一一处理这些细节。
由于前面年是一个一个加的,所以有可能加到0 年,把它变成1 年就好了。
因为月份是从1 开始数的,所以有可能会数到13 月。需要把年份加1 ,把月份变为1 。
输出时,要输出|y| ,若y<0 ,不要忘了输出BC。
- 设
好的那么 solve1() 就大功告成了。
solve2() 只需要在 solve1() 的基础上改一些地方。
- 每
400 年有146097 天,所以取N=\lfloor\frac{n}{146097}\rfloor 。 - 我们是从公元 1582 年 10 月 15 日开始数的,所以要把
n 减去2299171 ,这是从公元前 4713 年 1 月 1 日到公元 1582 年 10 月 15 日的天数;把y 的初始值赋成1582 ,再把n 加上287 ,这是从 1 月 1 日到 10 月 15 日的天数。 - 免去了判断公元前和零年的判断,因为最少到 1582 年。
考虑主函数里怎么写。考虑到换历法删除的
按儒略历手算可以算出公元 1582 年 10 月 4 日的儒略日是 solve1() 处理,否则将 solve2() 处理。
最后也是最重要的判断闰年。仔细读题可以发现,1582 年之前用的儒略历,只要年份是
到这就写完了,可是这些调了我 3 天。我的码风不怎么样,写了 70 行。
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,x;
int month[15]= {29,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int x) {
if(x<=1582) {//如果是儒略历判断闰年就是4年一闰
if(x<=0) x=-x-1;
return x%4==0;
}
if(x%400==0||(x%4==0&&x%100!=0)) return 1;//格里高利历判断闰年
return 0;
}
void solve1(int x) {
int N=x/146100;
int y=-4713+N*400;
if(y>1) y++;
x-=N*146100;//处理整400年
x++;
for(; x>366; y++) {//处理整年
int f=0;
if(y==0) y++;
f=check(y);
if(f) x-=366;
else x-=365;
}
int yue=1;
int f=0;
f=check(y);
if(f) month[2]=29;//如果是闰年,把month[2]设成29
for(; yue<=12&&x>month[yue]; yue++) x-=month[yue];//处理月
if(y==0) y=1;
if(yue==13) yue=1,y++;//处理细节
cout<<x<<' '<<yue<<' '<<abs(y);
if(y<0) cout<<" BC";
cout<<endl;
}
void solve2(int x) {
x-=2299171;
int y=1582,yue=1;
x+=287;
int N=x/146097;
y+=N*400;
x-=N*146097;
x++;
for(; x>366; y++) {
int f=0;
f=check(y);
if(f) x-=366;
else x-=365;
}
int f=0;
f=check(y);
if(f) month[2]=29;
for(; yue<=12&&x>month[yue]; yue++) x-=month[yue];
if(yue==13) yue=1,y++;
cout<<x<<' '<<yue<<' '<<y;
cout<<endl;
}
signed main() {
cin>>T;
while(T--) {
cin>>x;
month[2]=28;
if(x>=2299161) x+=10;
if(x<=2299160) solve1(x);//判断用solve1还是solve2
else solve2(x);
}
return 0;
}