csp-s2020 T1 Julian day

Keywords: Algorithm Simulation CSP

Title: [CSP-S2020] Julian day - Valleyhttps://www.luogu.com.cn/problem/P7075

After reading the question, we can see that this question is a simulation question about time.

According to the meaning of the question:

  1. The time is divided into two periods: the Julian calendar from January 1, 4713 BC to October 4, 1582 ad (inclusive); October 15, 1582   The Gregorian calendar is the day after (including).
  2. October 5 (inclusive) to October 14 (inclusive) in 1582: No, these dates were deleted, and October 15 after October 4 of that year.
  3. Gregorian calendar rule: January of each year   thirty-one   Day, February   twenty-eight   Days or   twenty-nine   Days, March   thirty-one   Days, April   thirty   Days, may   thirty-one   Days, June   thirty   Days, July   thirty-one   Days, August   thirty-one   Days, September   thirty   Days and October   thirty-one   Days, November   thirty   Days, December   thirty-one   Oh, my God. Among them, February of leap year is   twenty-nine   Days, weekdays   twenty-eight   Oh, my God. What was it then   four hundred   Multiple of, or date year is   four   Multiple of, but not   one hundred   The year is a leap year.
  4. Julian day rule: the number of days per month is the same as that in the Gregorian calendar, but as long as the year is   four   The multiple of is leap year.
  5. Year 0 does not exist, that is, the next year after year 1 B.C. is year 1 A.D. Therefore, years such as 1 BC, 5 BC, 9 BC, 13 BC... Should be regarded as leap years. Note that the year from A.D. 1 to A.D. 1582 is   four   The multiple of is leap year, i.e. ad 4, ad 8... And so on should be regarded as leap year. After A.D. 1589, it is applicable to the Gregorian calendar   four hundred   Multiple of, or date year is   four   Multiple of, but not   one hundred   The year is a leap year.

First, we can observe the data range of the topic at this time. We can't calculate day by day or year by year. According to the meaning of the topic analyzed above, before 1582, the Julian calendar was applicable. Every multiple of 4 is a leap year, that is, a cycle of 4 years. We can calculate the total number of cycles by division. Through our calculation, It is easy to calculate the number of days in a leap year cycle of the Julian calendar, that is, the number of days in three ordinary years and one leap year: 3 * 365 + 366 = 1461 days. After 1582, it is applicable to the Gregorian calendar. There is a cycle every 400 years, that is, 303 ordinary years and 97 leap years: 303 * 365 + 97 * 366 = 146097 days.

The number of days on October 4, 1582 is calculated as follows:

From 4713.1.1 to 1582.10.4 B.C., 4712 + 1582 = 6292 years.

Among them, there were 1179 leap years and 1178 * 3 ordinary years from 1 BC to 4713 BC. (because 1 BC, 5 BC ·································································································································.

From AD 1 to ad 1582, there were 395 leap years and 1187 ordinary years (including 1582). Therefore, the number of days is 395 * 366 + 1186 * 365 + October 4 of ordinary year = 577737 days.

To sum up: 2299160 days from 4713.1.1 to 1582.10.4 B.C. Take this number of days as the dividing line to divide the Julian calendar and the Gregorian calendar.

If the number of days < 2299160, it shall be calculated according to the Julian calendar. According to the previous analysis, we can know that there is a cycle every 4 years, and a cycle is 1461 days, so we can quickly calculate the cycle of the given days. The specific operations are as follows:

years=n/1461*4-4713;//years is the answer year, - 4713 is because BC
n%=1461;

If the number of days > 2299160, the Gregorian calendar is used for calculation every 400 years. The specific operations are as follows:

n-=2159351;   //Subtract the number of days on January 1, 1200, because there is a cycle every 400 years from year 1 A.D
years=(n/N)*400+1200;  //Add the minus 1200 years.
n%=N;

After the period calculation, the Julian and Gregorian calendars need to calculate the year in the period. The specific operations are as follows:

First, you need to judge whether the year is a leap year.

1. Leap year judgment of Julian calendar:

bool pd(int y){
	if((y%4==0&&y>0)||y%4==-1)return 1;
	else return 0;
}

2. Leap year judgment of Gregorian calendar:

bool pd1(int y){
	if(y%400==0||((y%4==0)&&(y%100!=0)))return 1;
	else return 0;
}

Year calculation:

1. Julian calendar:

if(years>=0) years++;//Because there is no year 0, it takes + + to 1 year to meet year 0.
while(n>=365){
	if(years==0) years++;
	if(pd(years)&&n>=366){  //pd() this function determines whether it is a leap year. If it is, it returns 1 instead of 0
	    n-=366;
		years+=1;
	}
	else if(!pd(years)&&n>=365){
		n-=365;
		years+=1;
	}
	else break;
}
if(years==0) years++;

2. Gregory Calendar

while(n>=365){
	if(pd1(years)&&n>=366){//pd1() is to judge whether it is a leap year. If yes, it returns 1 instead of 0
	    n-=366;
		years+=1;
	}
	else if(!pd1(years)&&n>=365){
		n-=365;
		years+=1;
	}
	else break;
}

After the year is calculated, the month and day need to be calculated. Because the Julian calendar and Gregorian calendar judge leap years in different ways, I wrote two functions to solve them respectively.

1. Julian calendar

int find_mon(long long years,long long x){
	int mon=1;
	if(pd(years)){
		int i=1;
		while(x>=r[i]){
			x-=r[i];i++;
			mon++;
		}
	}else{
		int i=1;
		while(x>=p[i]){
			x-=p[i];
			i++;
			mon++;
		}
	}
	days=x;
	return mon;
}

2. Gregory Calendar

int find_mon1(long long years,long long x){
	int mon=1;
	if(pd1(years)){
		int i=1;
		while(x>=r[i]){
			x-=r[i];i++;
			mon++;
		}
	}else{
		int i=1;
		while(x>=p[i]){
			x-=p[i];i++;
			mon++;
		}
	}
	days=x;
	return mon;
}

Then this question can be AC.

The AC code is as follows:

#include<iostream>
#include<cmath>
#include<cstdio> 
using namespace std;
int q;
long long days;
int N=146097;
int r[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int p[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool pd(int y){
	if((y%4==0&&y>0)||y%4==-1)return 1;
	else return 0;
}
bool pd1(int y){
	if(y%400==0||((y%4==0)&&(y%100!=0)))return 1;
	else return 0;
}
int find_mon(long long years,long long x){
	int mon=1;
	if(pd(years)){
		int i=1;
		while(x>=r[i]){
			x-=r[i];i++;
			mon++;
		}
	}else{
		int i=1;
		while(x>=p[i]){
			x-=p[i];
			i++;
			mon++;
		}
	}
	days=x;
	return mon;
}
int find_mon1(long long years,long long x){
	int mon=1;
	if(pd1(years)){
		int i=1;
		while(x>=r[i]){
			x-=r[i];i++;
			mon++;
		}
	}else{
		int i=1;
		while(x>=p[i]){
			x-=p[i];i++;
			mon++;
		}
	}
	days=x;
	return mon;
}
int main(){
	//freopen("P7075_5.in","r",stdin);
	//freopen("julian3.out","w",stdout);
	cin>>q;
	while(q--){
		long long  n;
		long long years,months;
		cin>>n;
		if(n>2299160){//Gregory 1582.10.15
			n-=2159351;
			years=(n/N)*400+1200;
			n%=N;
			while(n>=365){
				if(pd1(years)&&n>=366){
					n-=366;
					years+=1;
				}
				else if(!pd1(years)&&n>=365){
					n-=365;
					years+=1;
				}
				else break;
			}
			months=find_mon1(years,n);
		}
		else{//Before 1582.10.4 Julian calendar 
			years=n/1461*4-4713;
			n%=1461;
			if(years>=0) years++;
			while(n>=365){
				if(years==0) years++;
				if(pd(years)&&n>=366){
					n-=366;
					years+=1;
				}
				else if(!pd(years)&&n>=365){
					n-=365;
					years+=1;
				}
				else break;
			}
			if(years==0) years++;
			months=find_mon(years,n);
		}
		if(years<0)	
			cout<<days+1<<" "<<months<<" "<<abs(years)<<" BC"<<endl;
		else 
			cout<<days+1<<" "<<months<<" "<<years<<endl;
	}
	return 0;
} 

Posted by tmswenson on Tue, 19 Oct 2021 19:02:08 -0700