P7075
分析
听说可以用二分做,但是我直接模拟。
最开始我先直接把所有的日子直接转换成儒略历。
若转换后没有超过公元年,那么直接输出,结束。
若超过公元年,先给年号 \(+1\) (跳过 \(0\) 年),然后再判断:
若没有超过 1582.10.5,直接输出。
否则,给天数加上十天,然后开始补格里高利历与儒略历之间的差距:每 400 年 3 天的差距。
补完之后输出就可以了。
注意你需要对这个做法进行加速,不然会 TLE 10 pts。
细节在代码里有。
代码
比较丑陋。考场上炸了 90 pts,因为第一次膜 \(1461\) 时没有特殊处理导致 day
直接等于 \(0\),直接爆炸。后来被官方数据又 hack 一个点,是中间的地方膜 \(146097\) 时没有特殊处理的原因。
#include <bits/stdc++.h>
using namespace std;
template <typename T>
T read(void) {
T f = 1, num = 0;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -f;
c = getchar();
}
while (c >= '0' && c <= '9') {
num = (num << 3) + (num << 1) + (c ^ 48);
c = getchar();
}
return f * num;
}
const int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline int daysBefore(int year, int month) { //儒略历天数
if (month != 2) return days[month - 1];
if ((year > 0 && year % 4 == 0) || (year < 0 && year % 4 == -1)) return 29;
return 28;
}
inline int daysNear(int year, int month) { //格里高利历天数
if (month != 2) return days[month - 1];
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return 29;
return 28;
}
inline int daysInYear(int year) { //格里高利历每年天数
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return 366;
return 365;
}
int main() {
int Q = read<int>();
while (Q--) {
long long day = read<long long>();
int year = -4713 + day / 1461 * 4, month = 1;
//4年一个循环,4年天数共365*4+1=1461
day %= 1461;
day++; //注意开始的时候是一月一号,所以要加一
//公元年特判
if (year >= 0) year++;
//暴力弥补剩下的月份
while (day > daysBefore(year, month)) {
day -= daysBefore(year, month);
if (++month == 13) month = 1, year++;
if (year == 0) year++;
}
if (year < 0) //公元前
printf("%lld %d %d BC\n", day, month, -year);
else {
if (year > 1582 || (year == 1582 && month > 10) || (year == 1582 && month == 10 && day > 4)) {
//如果超过了1582.10.4
day += 10; //补上十天
//暴力处理月份
if (daysBefore(year, month) < day) {
day -= daysBefore(year, month);
if (++month == 13) month = 1, year++;
}
//每400年补上3天
long long plus = (year - 1600) / 400 * 3;
//暴力枚举不足400年的剩余部分
for (register int i = (year - 1600) / 400 * 400 + 1600; i < year || (i == year && month > 2); i += 100)
if (i % 400 != 0) plus++;
//加上
day += plus;
//先将没有满的年份补满
while (daysNear(year, month) < day) {
day -= daysNear(year, month);
if (++month == 13) {
month = 1, year++;
break;
}
}
//每400年一个轮回,400*365+100-4+1=146097天
day--, year += day / 146097 * 400, day %= 146097, day++;
while (daysInYear(year) < day) day -= daysInYear(year++); //对于多余的年份加速处理
//处理剩余出的月份
while (daysNear(year, month) < day) {
day -= daysNear(year, month);
if (++month == 13) month = 1, year++;
}
}
printf("%lld %d %d\n", day, month, year);
}
}
return 0;
}