【CSP2020】 T1儒略日

NOIPCSP2020终于结束辣,可是这跟我一个大一学生有什么关系呢?,作为曾经的OI狗,也作为准备冲击ACM校队的一名蒟蒻,我决定做一做今年的题。

题目链接
https://www.luogu.com.cn/problem/P7075?contestId=37022

本题是一道显然的大模拟,思路很简单,但是需要考虑的细节实在是太多力QwQ,窝写了4个多小时才A掉此题(想必如果真在赛场就要喜提省四了罢),最终发现少写了一个return。。。

简单讲一下一些优化技巧吧,首先,可以写一个函数计算每年的第几天是几月几日,减少大量重复操作。而且,接下来只要考虑年份和天数,去除了干扰因素。同时,利用题目信息,将问题分段。对于格里高利历,有400和100对闰年的影响,可以将1582年到1599年单独分一组,这样,从1600年1月1日开始,就可以400年一个周期,变得有规律了。

代码

#include<cstdlib>
#define ll long long
using namespace std;
int d[2][13]={0,31,28,31,30,31,30,31,31,30,31,30,31,
0,31,29,31,30,31,30,31,31,30,31,30,31
};
struct date{
	bool BC;
	int month,day;
	ll year;
};
date f(int x,int flag,int isBC){
	int i;
	date ans;
	ans.BC=isBC;
	for(i=1;i<=12;i++){
		if(x<=d[flag][i]){
			ans.month=i;ans.day=x;
			return ans;
		}
		x-=d[flag][i];
	}
}
date julian(ll x){
	date ans;
	int tmp=4713*365+4712/4+1;
	if(x<=tmp){//BC
		ll t=(x-1)/(4*365+1);
		ll r=x-t*(4*365+1);
		ll y=4713-t*4;
		if(r>366){
			y--;r-=366;
		}
		else{
			ans=f(r,1,1);
			ans.year=y;
			return ans;
		}
		if(r>365){
			y--;r-=365;
		}
		else{
			ans=f(r,0,1);
			ans.year=y;
			return ans;
		}
		if(r>365){
			y--;r-=365;
		}
		else{
			ans=f(r,0,1);
			ans.year=y;
			return ans;
		}
		ans=f(r,0,1);
		ans.year=y;
		return ans;
	}
	else{//AD
		x-=tmp;
		tmp=1581*365+1582/4+277;
		if(x<=tmp){//julian
			ll t=(x-1)/(4*365+1);
			ll r=x-t*(4*365+1);
			ll y=4*t+1;
			if(r>365){
				y++;r-=365;
			}
			else{
				ans=f(r,0,0);
				ans.year=y;
				return ans;
			}
			if(r>365){
				y++;r-=365;
			}
			else{
				ans=f(r,0,0);
				ans.year=y;
				return ans;
			}
			if(r>365){
				y++;r-=365;
			}
			else{
				ans=f(r,0,0);
				ans.year=y;
				return ans;
			}
			ans=f(r,1,0);
			ans.year=y;
			return ans;
		}
		else{//new
			x+=10-tmp;
			if(x<=88+(1600-1583)*365+4){//before 1600 1 1
				if(x<=88){//this year
					ans=f(x+277,0,0);
					ans.year=1582;
					return ans;
				}
				else{
					x-=88;
					for(int i=1583;i<1600;i++){
						int kkk;
						if(!(i%4)) kkk=1;
						else kkk=0;
						if(x<=365+kkk){
							ans=f(x,kkk,0);
							ans.year=i;
							return ans;
						}
						x-=365+kkk;
					}
				}
			}
			else{//after 1600 1 1
				x-=88+(1600-1583)*365+4;
				ll t=(x-1)/(400*365+100-4+1);
				ll y=1600+t*400;
				x-=t*(400*365+100-4+1);
				if(x<=100*365+25){
					ll tt=(x-1)/(4*365+1);
					ll r=x-tt*(4*365+1);
					y+=tt*4;
					if(r>366){
						y++;r-=366;
					}
					else{
						ans=f(r,1,0);
						ans.year=y;
						return ans;
					}
					if(r>365){
						y++;r-=365;
					}
					else{
						ans=f(r,0,0);
						ans.year=y;
						return ans;
					}
					if(r>365){
						y++;r-=365;
					}
					else{
						ans=f(r,0,0);
						ans.year=y;
						return ans;
					}
					ans=f(r,0,0);
					ans.year=y;
					return ans;
				}
				else{
					x-=(100*365+25);
					y+=100;
					ll tt=(x-1)/(100*365+25-1);
					ll r=x-tt*(100*365+25-1);
					y+=tt*100;
					if(r>31+28) r++;
					tt=(r-1)/(4*365+1);
					r=r-tt*(4*365+1);
					y+=tt*4;
					if(r>366){
						y++;r-=366;
					}
					else{
						ans=f(r,1,0);
						ans.year=y;
						return ans;
					}
					if(r>365){
						y++;r-=365;
					}
					else{
						ans=f(r,0,0);
						ans.year=y;
						return ans;
					}
					if(r>365){
						y++;r-=365;
					}
					else{
						ans=f(r,0,0);
						ans.year=y;
						return ans;
					}
					ans=f(r,0,0);
					ans.year=y;
					return ans;
				}
			}
		}
	}
}
int main(){
	int T,i,j;
	ll x;
	date ans;
	// freopen("julian3.in","r",stdin);
	// freopen("out.txt","w",stdout);
	scanf("%d",&T);
	for(i=1;i<=T;i++){
		scanf("%lld",&x);
		ans=julian(x+1);
		printf("%d %d %lld",ans.day,ans.month,ans.year);
		if(ans.BC) printf(" BC");
		printf("
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/landmine-sweeper/p/13956042.html