儒略日(CSP S2 第一题)

儒略日

题目

为了简便计算,天文学家们使用儒略日(Julian day)来表达时间。
所谓儒略日,其定义为从公元前 4713年 1 月 1 日正午 12点到此后某一时刻间所经过的天数,不满一天者用小数表达。
若利用这一天文学历法,则每一个时刻都将被均匀的映射到数轴上,从而得以很方便的计算它们的差值。现在,给定一个不含小数部分的儒略日,请你帮忙计算出该儒略日(一定是某一天的中午 12点)所对应的公历日期
我们现行的公历为格里高利历(Gregorian calendar),它是在公元 1582
年由教皇格里高利十三世在原有的儒略历(Julian calendar)的基础上修改得到的(注:儒略历与儒略日并无直接关系)。
具体而言,现行的公历日期按照以下规则计算:

  1. 公元 1582年 10 月 15 日(含)以后:适用格里高利历,每年一月 31 天、二月 28 天或 29 天、三月 31 天、四月 30 天、五月 31 天、六月 30 天、七月 31 天、八月 31 天、九月 30 天、十月 31 天、十一月 30 天、十二月 31 天。其中,闰年的二月为 29 天,平年为 28 天。当年份是 400 的倍数,或日期年份是 4 的倍数但不是 100的倍数时,该年为闰年。
  2. 公元 1582年 10 月 5 日(含)至 10 月 14 日(含):不存在,这些日期被删除,该年 10 月 4 日之后为 10 月 15日。
  3. 公元 1582年 10 月 4 日(含)以前:适用儒略历,每月天数与格里高利历相同,但只要年份是 4的倍数就是闰年。
  4. 尽管儒略历于公元前 45年才开始实行,且初期经过若干次调整,但今天人类习惯于按照儒略历最终的规则反推一切 1582 年 10 月 4 日之前的时间。注意,公元零年并不存在,即公元前 1 年的下一年是公元 1 年。因此公元前 1 年、前 5 年、前 9 年、前 13 年……以此类推的年份应视为闰年。
    输入格式
    第一行一个整数 Q,表示询问的组数。
    接下来 Q行,每行一个非负整数 ri,表示一个儒略日。
    输出格式
    对于每一个儒略日 ri,输出一行表示日期的字符串 si。
    共计 Q行。
    输入样例1
    3
    10
    100
    1000
    输出样例1:
    11 1 4713 BC
    10 4 4713 BC
    27 9 4711 BC
    输入样例2:
    4
    1721424
    2000000
    3000000
    4000000
    输出样例2:
    1 1 1
    14 9 763
    15 8 3501
    12 7 6239
数据范围

Q <= 105 , ri <= 109

代码实现
//大模拟
//1583年后四百年一循环,利用此规律将每个询问降为O(1)
#include <iostream>
typedef long long LL;
const int D = 3146100;//略大于预处理天数
using namespace  std;

int T = 146097;//四百年总天数,其中97个闰年
int T1 = 3000000;
int days[D],mon[D],year[D];
const int months[13] = {0, 31, 28, 31, 30 , 31, 30, 31, 31, 30, 31, 30, 31 };

bool isleapyear(int y)
{
	if(y < 0) return (y % 4 == -1);
    if(y >=1 && y <= 1582 ) return (y % 4 == 0);
    return y % 400 == 0 || (y % 4 == 0 && y % 100);
}
int getdays(int y, int m)
{
    if(m == 2) return months[m] + isleapyear(y);
    return months[m];    
}
void predeal()
{
	int d = 1, m = 1, y = -4713;
	int r = T + T1;//预处理天数 
	for(int k = 0; k <= r; k ++)
	{
		days[k] = d, mon[k] = m, year[k] = y;//assign
        if (d == 4 && m == 10 && y == 1582) {
            d = 15;
        } else if ( getdays(y, m) == d) {
            d = 1;
            if (m == 12) {
                m = 1, y ++;
                if (y == 0) y++;
            } else m++;
        } else d++;	
	}
}

int main()
{   
    predeal();
    int q;
    cin >> q;
    while (q --)
    {
        LL r;
        scanf("%lld",&r);
        if (r <= T + T1)
        {
        	if (year[r] < 0) printf("%d %d %d BC\n", days[r], mon[r], -year[r]);
             else printf("%d %d %d\n", days[r], mon[r], year[r]);
		}
        else {
            int target = T1 + ((r - T1) % T);
            printf("%d %d %d\n", days[target], mon[target], year[target] + (r - T1)/T * 400 );
        
        }

    }

    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值