题解:P7075 [CSP-S2020] 儒略日

· · 题解

这篇题解本来有很多前言,但是说多了都是泪,还是不说了。

题意

给定 n,请你求从公元前 4713 年 1 月 1 日往后数 n 天的日期。

简明的题意,屎山的代码。

思路

发现公元 1582 年 10 月 4 日之后改了历法,那么这里就是一个转折点。为了防止出错,我选择将此之前和此之后分开处理,写成 solve1()solve2()

好的那么 solve1() 就大功告成了。

solve2() 只需要在 solve1() 的基础上改一些地方。

  1. 400 年有 146097 天,所以取 N=\lfloor\frac{n}{146097}\rfloor
  2. 我们是从公元 1582 年 10 月 15 日开始数的,所以要把 n 减去 2299171,这是从公元前 4713 年 1 月 1 日到公元 1582 年 10 月 15 日的天数;把 y 的初始值赋成 1582,再把 n 加上 287,这是从 1 月 1 日到 10 月 15 日的天数。
  3. 免去了判断公元前和零年的判断,因为最少到 1582 年。

考虑主函数里怎么写。考虑到换历法删除的 10 天,若该日期在公元 1582 年 10 月 15 日(含)以后,直接把 n 加上 10 即可。

按儒略历手算可以算出公元 1582 年 10 月 4 日的儒略日是 2299160。所以判断若 n\le2299160,按儒略日用 solve1() 处理,否则将 n 加上 10,用 solve2() 处理。

最后也是最重要的判断闰年。仔细读题可以发现,1582 年之前用的儒略历,只要年份是 4 的倍数就闰,否则就是我们熟悉的闰年法。对于公元前的年份 x,应把它看做 -x-1 年。

到这就写完了,可是这些调了我 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;
}