题解 CSP 2020S T1- 儒略日

题解 - P 7075 \mathrm{P7075} P7075

题目意思

题目传送门

S o l \mathrm{Sol} Sol

给一种二分的做法?

我们考虑先做 公元前 4713 ∼ 1 4713 \sim 1 47131 年,我们预处理经过整 x x x 年需要几天。那么我们可以快速算出 n n n 天是在哪一年?

找到那一年我们只要 12 个月份依次模拟一遍即可。这样已经可以得到 40 40 40 分。

然后我们考虑公园 $1 \sim 10^9 $ 年。我们考虑二分 n n n 天后在哪一年。我们首先要从公元 1 1 1 年开始二分,所以 n n n 要减去 1721424 。二分如何判定?假设当前年为 y e a r year year


如果 y e a r ≤ 1582 year\leq 1582 year1582 那么闰年个数即为 y e a r 4 \frac{year}{4} 4year,那么到 y e a r year year 年的天数为: 365 × y e a r + ( y e a r 4 ) 365\times year+(\frac{year}{4}) 365×year+(4year)

否则稍微容斥一下得到闰年个数为: g s = 1582 4 + y e a r 4 − 1581 4 + y e a r 400 − 1581 4 − y e a r 100 + 1581 4 gs=\frac{1582}{4}+\frac{year}{4}-\frac{1581}{4}+\frac{year}{400}-\frac{1581}{4}-\frac{year}{100}+\frac{1581}{4} gs=41582+4year41581+400year41581100year+41581,

那么到 y e a r year year 年的天数为: 365 × y e a r + g s − 10 365\times year+gs-10 365×year+gs10 减去 10 10 10 是因为 1582 1582 1582 年有 10 10 10 天是要去掉的。


最后我们只要再枚举 12 12 12 个月份即可,注意细节!!

时间复杂度 O ( q × log ⁡ ( 1 0 9 ) + q × 12 ) O(q\times \log(10^9)+q\times 12) O(q×log(109)+q×12)

C o d e \mathrm{Code} Code

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ ) 
#define Dow(i,a,b) for ( int i=(a);i>=(b);i-- ) 
#define int long long 
using namespace std;
inline int read()
{
	int x=0; char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10ll+(ch^48),ch=getchar();
	return x;
}
int Q,n,fl,day[15],sum[3000005],sum1[3000005],sumt[3000005];
inline void first_step()
{
	int x=upper_bound(sum1+1,sum1+4714,n)-sum1-1;
	int year=4713-x;
	n-=sum1[x];
	if(!n) 
	{
		if(!year) printf("%d %d %d\n",1,1,year+1);
		else printf("%d %d %d BC\n",1,1,year);
	}
	else 
	{
		For(j,1,12) 
		{
			if(fl) break;
			int Day=28;
			if(j!=2) Day=day[j];
			else Day=((year-1)%4==0)?29:28;
			if(n>Day) n-=Day;
			else 
			{
				fl=1;
				if(n+1<=Day) printf("%d %d %d BC\n",n+1,j,year);
				else if(j!=12) printf("%d %d %d BC\n",1,j+1,year);
				else 
				{
					if(year-1!=0) printf("%d %d %d BC\n",1,1,year);
					else printf("%d %d %d\n",1,1,1);
				}
				n=0;
			}	
		}
	}
}
inline void third_step()
{
	int l=1,r=1e9,x=0;
	while(l<=r)
	{
		int mid=l+r>>1,tot_year=365*mid,rn_gs=0;
		if(mid>=1582) tot_year-=10,rn_gs=(1581ll/4ll)+(mid/4ll)-(1581ll/4ll)+(mid/400ll)-(1581ll/400ll)-(mid/100ll)+(1581ll/100ll);
		else rn_gs=mid/4ll;
		tot_year+=rn_gs;
		if(tot_year<=n) l=mid+1,x=mid; 
		else r=mid-1;
	}
	int year=x+1;
	if(year<=1582) n-=(x*365+(x/4ll));
	else n-=(x*365+(1582ll/4ll)+(x/4ll)-(1581ll/4ll)+(x/400ll)-(1581ll/400ll)-(x/100ll)+(1581ll/100ll)-10);
	if(!n) printf("%d %d %d\n",1,1,year);
	else 
	{
		For(j,1,12) 
		{
			if(fl) break;
			int Day=28;
			if(j!=2) Day=day[j];
			else 
			{
				if(year<=1582&&j<=10) Day=(year%4==0)?29:28;
				else if(year%400==0||(year%4==0&&year%100!=0)) Day=29;
			}
			if(year==1582&&j==10) 
			{
				if(n<=3) printf("%d %d %d\n",n+1,10,1582),fl=1,n=0;
				else Day-=10;
			}
			if(n>=Day) n-=Day;
			else if(!fl)
			{
				fl=1;
				if(n+1<=Day) 
				{
					if(year==1582&&j==10) printf("%d %d %d\n",n+11,j,year);
					else printf("%d %d %d\n",n+1,j,year);
				}
				else if(j!=12) printf("%d %d %d\n",1,j+1,year);
				else printf("%d %d %d\n",1,1,year+1);
				n=0;
			}
		}
	}
}
signed main()
{
	Dow(i,4713,1) sum1[4713-i+1]=sum1[4713-i]+365+((i-1)%4==0);
	Q=read();
	day[1]=day[3]=day[5]=day[7]=day[8]=day[10]=day[12]=31,day[4]=day[6]=day[9]=day[11]=30;
	for (;Q--;) 
	{
		fl=0;
		n=read();
		if(n<=1721424) first_step();
		else n-=1721424,third_step();
	}
	return 0;
}
		
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值