CSP-S 2020 儒略日切后感

Phizo Lv1

我真的是服了儒略日了。

他前… 原本我前天晚上一点事都没有,前天晚上偶然,我的同学,跟我问我,CSP 2020 的提高组的那个… T… 提高组的那个 T1 为什么还没切,好嘛。我打开洛谷一看,发现他给了个莫名奇妙的题干,跟我说这个,给定儒略日让我输出对应公历,我想着,哎?我没有,这个 C++ 的日历啊,我可以用 Java 啊,然后我就打开 IDEA 进来一看,看到,哎?好像也不能用 Date 算儒略日啊。然后我看一下,哎不对啊,我 1582 年 10 月的 5 号到 14 号呢,为什么没有了呀?为什么这里 4 号跳到 15 号了呀?我原本 4 年 1 闰为什么变成 400 年 97 闰了呀?完蛋了呀。

我前天没时间写,昨天上午水了点题来了感觉才打算开始写。公元前的写了二十分钟调了二十分钟,然后 1582 年以前的一直到下午才调出来。这些都好说,包括那消失的 10 天,你 t += 10 就好了。后来,我 nm 调了半个下午和一个晚上,也没把 1582 年往后的 sb 闰年机制调出来。儒略!格里高利!看到了吗!什么 rz 啊。啊?我动不动就爆 0 月 366 号和 0 月 0 号,最后血压溢出了才打算好好用 Excel 列个表。好嘛。每 100 年我公历就算歪一天。我真的烦
死这个儒略日了!

昨天晚上将近十一点,我拿对拍机拍了几分钟,发现跟题解里嫖的 std 答案一模一样。我就直接往洛谷上一交。我以为能 AC 的,但是只拿了 80?最后两个还不是蛙,还是瑞了,下数据本地跑提示 5477。但是我数组开够了呀,怎么可能越界呀。最后输出 day_of_year 一看,我艹,两万多,不瑞才有鬼了。

我真的是服了我,我真的,我很生气非常生气,那儒略日就是个垃圾,我看今天谁敢糊儒略日!

题目要求:给定儒略日,输出对应公历日期。
由于直接处理儒略日很难下手,我们可以先将其转换为距离公元 日正午 点的天数。

1
2
3
4
day = -1721423;
r = read();
day += r;
process(day); // 在 process 函数中,我们使用 t 代表这里的 day

公元前(

为了方便,我们先将 换成相反数。

1
t = -t;

接下来的大体思路是,先通过某种手段获取该日期的年份(year),然后再得到该日期在当年排在第几天(day_of_year),最后通过查表得到月和日。这个思路同样适用于接下来的两种情况。

由于在 日之前一定是每 年就会有 个闰年,因此相邻 年的总天数一定是 。换句话说,在 日之前,每年平均有 天。我们便可以用 除以这个数来得到年数。

1
year = t * 4 / 1461;

接下来用 year % 4 是否等于 来判断闰年。

1
leap = year % 4 == 0;

通过用 year 反推出的天数减去真正的天数 就可以得知该日期在当年排在第几天(day_of_year

1
2
3
4
5
day_of_year = (year + 1) * 1461 / 4 - t;

if (leap || year % 4 == 1 || year % 4 == 2) {
day_of_year++;
}

不要问我为什么 year 以及后面为什么只要 就要再让 day_of_year,具体来说我也不知道。(问就是拿对拍机拍出来的经验)
最后发现 yearyear++ 即可解决。

公元 年—公元 年(

首先,判断日期是否大于或等于 日,如果是,则让

1
2
3
if (t >= 577738) {
t += 10;
}

然后获取年份。

1
2
3
4
5
year = t * 4 / 1461;

if (year * 1461 == t * 4) { // 如果 t 恰好能被 365.25 整除
year = (t - 1) * 4 / 1461; // 别问,问了还是拿对拍机拍出来的经验
}

判断是否为闰年。

1
leap = (year + 1) % 4 == 0;

获取该日期在当年所排天数。(同时让 year

1
day_of_year = t - year++ * 1461 / 4;

公元 年—公元 年(

之前不需要考虑那些能被 整除但仍然是平年的年份。而在这个情况下必须要把它们考虑进去了。

对于每 年来说,一定有 个闰年,总天数为 ,平均每年有 天。遗憾的是,如果我们用 除以这个数,它并不能实现完美拟合, 号的情况不在少数。这归根到底是由闰年的分布不平均导致的。

获取年份的手段要稍加变化。

我们不妨设置一个一维数组,记为 dty,即“day to year”,其中 年中的第 dty[i] 天对应第 日。
为什么不让第 dty[i] 年的 日对应 年中的第 天呢?这样查起来方便,能够做到时间复杂度为 的查询。但是我们发现,这样算下来需要开辟一个长度为 的数组,这波用时间换空间是有点亏的。

而一个长度为 的数组听起来也不像是一个懒癌晚期能码出来的。
因此,我们可以码一个程序来帮我们完成这项工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <cstdio>
using namespace std;
int main() {
printf("int dty[402] = {0, 0");
int sum = 0;
for (int i = 1; i <= 400; i++) {
if (i % 400 == 0 || (i % 100 != 0 && i % 4 == 0)) {
sum += 366;
} else {
sum += 365;
}
printf(", %d", sum);
}
printf("};");
return 0;
}

有了这个数组之后,我们只需对 稍加处理就能得到理论上正确的年份。

1
2
3
4
5
6
7
8
t -= 2; // 我也不知道为什么
year = t / 146097 * 400; // 获取精确到百位的年份
int day_of_400_years = t % 146097; // 用 400 年的总天数对 t 取模,得到该日期在 400 年内排第几天

if (day_of_400_years == 0) { // 特判,如果 t 正好能被 400 年总天数整除
day_of_400_years = 146097;
year -= 400;
}

终于轮到获取年份的环节了。

1
2
3
4
5
6
7
for (int i = 1; i <= 400; i++) { // 遍历年份
if (dty[i] < day_of_400_years && day_of_400_years <= dty[i + 1]) {
year += i; // 将已精确到百位的年份加上 i,得到精确到个位的年份
day_of_year = day_of_400_years - dty[i]; // 顺便得到该日期在这一年中的天数
break; // 找到了就直接 break,不要跟它逼逼赖赖
}
}

判断是否为闰年。

1
leap = year % 400 == 0 || (year % 100 != 0 && year % 4 == 0);

以上就是对三种情况的处理。

我们现在有了年份以及日期在当年内的天数。接下来需要算出该日期所在的具体月份,以及它在当月内的天数。

但貌似一年内的各个月份的天数对我们也不是特别友好:

一三五七八十腊,三十一天永不差。
四六九冬三十整,惟有二月二十八,闰年还要把一日加。

我们延续 的思路:创建两个二维数组,分别叫做 doytm(day-of-year to month)和 mtdoy(month to day-of-year)。其中:

  • doytm[i][0] 表示如果当前年为平年,第 i 天所处月份;
  • doytm[i][1] 表示如果当前年为闰年,第 i 天所处月份;
  • mtdoy[i][0] 表示如果当前年为平年,前 i 个月份累加的天数和;
  • mtdoy[i][1] 表示如果当前年为闰年,前 i 个月份累加的天数和。

生成 doytm 数组的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <cstdio>
using namespace std;
int a[366], b[367];
int main() {
printf("int doytm[367][2] = {");
for (int i = 1; i <= 365; i++) {
if (i <= 31) {
a[i] = 1;
} else if (i <= 31 + 28) {
a[i] = 2;
} else if (i <= 31 + 28 + 31) {
a[i] = 3;
} else if (i <= 31 + 28 + 31 + 30) {
a[i] = 4;
} else if (i <= 31 + 28 + 31 + 30 + 31) {
a[i] = 5;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30) {
a[i] = 6;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30 + 31) {
a[i] = 7;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31) {
a[i] = 8;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30) {
a[i] = 9;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) {
a[i] = 10;
} else if (i <= 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) {
a[i] = 11;
} else {
a[i] = 12;
}
}
for (int i = 1; i <= 366; i++) {
if (i <= 31) {
b[i] = 1;
} else if (i <= 31 + 29) {
b[i] = 2;
} else if (i <= 31 + 29 + 31) {
b[i] = 3;
} else if (i <= 31 + 29 + 31 + 30) {
b[i] = 4;
} else if (i <= 31 + 29 + 31 + 30 + 31) {
b[i] = 5;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30) {
b[i] = 6;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30 + 31) {
b[i] = 7;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31) {
b[i] = 8;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30) {
b[i] = 9;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) {
b[i] = 10;
} else if (i <= 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) {
b[i] = 11;
} else {
b[i] = 12;
}
}
for (int i = 1; i <= 365; i++) {
printf("{%d, %d}, ", a[i], b[i]);
}
printf("{0, %d}};", b[366]);
return 0;
}

生成 mtdoy 数组的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <cstdio>
using namespace std;
int m[13][2] = {{0, 0}, {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}};
int main() {
int sum1 = 0, sum2 = 0;
printf("int mtdoy[13][2] = {");
for (int i = 0; i <= 12; i++) {
sum1 += m[i][0];
sum2 += m[i][1];
printf(i == 12 ? "{%d, %d}" : "{%d, %d}, ", sum1, sum2);
}
printf("};");
return 0;
}

接下来的事情就变得很简单了:

想要求得月份,访问数组即可。

1
month = doytm[day_of_year][leap];

对于当月的日期,用前 个月份累加的天数和对 day_of_year 取模即可。

1
day = mod(day_of_year, mtdoy[month - 1][leap]);

为什么要自定义取模函数?
想一下,如果当前月份为 月,则前 个月份累加的天数和就是
因此,当我们试图直接使用 % 运算符取余时, Dev-C++ 会亲切地告诉你:

1
Process exited after 0.306 seconds with return value 3221225620

假设我们要计算 ,那么当 时,我们要进行特判:直接返回

1
2
3
4
5
6
7
8
// large_type 表示大数据类型,可以是 long long,也可以是 __int128
inline int mod(large_type a, int p) {
if (p == 0) {
return a;
}

return a % p;
}

处理完月和日之后,我们就可以愉快地输出了。

1
2
3
4
5
6
7
8
9
10
11
12
13
print(day);
putchar(' ');
print(month);
putchar(' ');
print(year);

if (bc) {
putchar(' ');
putchar('B');
putchar('C');
}

putchar('\n');

代码倒是写完了,如何验证正确性?
Tip: 即使在某些 OJ 上能 AC,也不一定代表你的程序完全正确。

这道题的数据很好生成,输出 个属于区间 的随机数即可。(

为了更方便的调试,建议按顺序生成数据。
因此,便有了如下的数据生成机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Scanner;

public class JulianCalendar {

public static void main(String[] args) throws IOException {
File config = new File("julianConfig.txt");
File julianIn = new File("julian.in");
Scanner scanner = new Scanner(config);
BigInteger i = scanner.nextBigInteger();
BigInteger n = i.add(new BigInteger("100000"));
BufferedWriter writer = new BufferedWriter(new FileWriter(julianIn));
writer.write("100000\n");
while (i.compareTo(n) == -1) {
writer.write(i.toString() + '\n');
i = i.add(BigInteger.ONE);
}
writer.close();
System.out.println(i);
BufferedWriter configWriter = new BufferedWriter(new FileWriter(config));
configWriter.write(i.toString());
configWriter.close();
}
}

使用方法:首先将这段代码编译成 JAR 文件,将其放到含有标准程序和待测试程序的目录中,并且在这个目录中新建文本文档 julianConfig.txt,在其内输入一个整数,表示你希望生成从哪里开始的数据。

确保标准程序和待测试程序都已添加文件输入和输出,并且输入的文件名已指定为 julian.in
假设你的目录为 D:\OI,你的标准程序名为 julianstd.exe 且输出文件名为 julianstd.out,待测试程序名为 julian.exe 且输出文件名为 julian.out,新建一个批处理文件,输入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@echo off
:loop
java -jar Julian.jar
start /b "" "D:\OI\julianstd.exe"
start /b "" "D:\OI\julian.exe"
:find1
choice /t 1 /d y /n >nul
tasklist|find /i "julian.exe" >nul
if %errorlevel% == 0 (
goto find1
) else (
goto find2
)
:find2
tasklist|find /i "julianstd.exe" >nul
if %errorlevel% == 0 (
goto find2
) else (
goto compare
)
:compare
fc julianstd.out julian.out
if %errorlevel% == 0 (
goto loop
)
pause

保存批处理文件,双击运行,即可开始进行程序正确性的验证。

如果你的答案与标准程序的答案存在差异,则批处理会指出差异并停止验证。

再贴一个随机数据生成机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <bits/stdc++.h>
using namespace std;
inline void print(unsigned long long x) {
char f[200];
unsigned long long tmp = x > 0 ? x : -x;

if (x < 0) {
putchar('-');
}

int cnt = 0;

while (tmp > 0) {
f[cnt++] = tmp % 10 + '0';
tmp /= 10;
}

while (cnt > 0) {
putchar(f[--cnt]);
}
putchar('\n');
}
int main() {
freopen("julian.in", "w", stdout);
srand(time(0));
int n = rand() % 50000;
print(n);

for (int i = 1; i <= n; i++) {
print((unsigned long long) rand() << 48 | (unsigned long long) rand() << 32 | (unsigned long long) rand() << 16 | rand());
}
}

使用时把批处理中的 java -jar Julian.jar 换成你的随机数据生成机的可执行文件名即可。

在洛谷、一本通上都能拿满分的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <cstdio>
#include <cmath>
#define large_type __int128
using namespace std;
large_type q, r, day;
int mtdoy[13][2] = {{0, 0}, {31, 31}, {59, 60}, {90, 91}, {120, 121}, {151, 152}, {181, 182}, {212, 213}, {243, 244}, {273, 274}, {304, 305}, {334, 335}, {365, 366}};
int doytm[367][2] = {{0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {3, 2}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 3}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {5, 4}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {6, 5}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {7, 6}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {8, 7}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 8}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {9, 9}, {10, 9}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {10, 10}, {11, 10}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {11, 11}, {12, 11}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {12, 12}, {0, 12}};
int dty[402] = {0, 0, 365, 730, 1095, 1461, 1826, 2191, 2556, 2922, 3287, 3652, 4017, 4383, 4748, 5113, 5478, 5844, 6209, 6574, 6939, 7305, 7670, 8035, 8400, 8766, 9131, 9496, 9861, 10227, 10592, 10957, 11322, 11688, 12053, 12418, 12783, 13149, 13514, 13879, 14244, 14610, 14975, 15340, 15705, 16071, 16436, 16801, 17166, 17532, 17897, 18262, 18627, 18993, 19358, 19723, 20088, 20454, 20819, 21184, 21549, 21915, 22280, 22645, 23010, 23376, 23741, 24106, 24471, 24837, 25202, 25567, 25932, 26298, 26663, 27028, 27393, 27759, 28124, 28489, 28854, 29220, 29585, 29950, 30315, 30681, 31046, 31411, 31776, 32142, 32507, 32872, 33237, 33603, 33968, 34333, 34698, 35064, 35429, 35794, 36159, 36524, 36889, 37254, 37619, 37985, 38350, 38715, 39080, 39446, 39811, 40176, 40541, 40907, 41272, 41637, 42002, 42368, 42733, 43098, 43463, 43829, 44194, 44559, 44924, 45290, 45655, 46020, 46385, 46751, 47116, 47481, 47846, 48212, 48577, 48942, 49307, 49673, 50038, 50403, 50768, 51134, 51499, 51864, 52229, 52595, 52960, 53325, 53690, 54056, 54421, 54786, 55151, 55517, 55882, 56247, 56612, 56978, 57343, 57708, 58073, 58439, 58804, 59169, 59534, 59900, 60265, 60630, 60995, 61361, 61726, 62091, 62456, 62822, 63187, 63552, 63917, 64283, 64648, 65013, 65378, 65744, 66109, 66474, 66839, 67205, 67570, 67935, 68300, 68666, 69031, 69396, 69761, 70127, 70492, 70857, 71222, 71588, 71953, 72318, 72683, 73048, 73413, 73778, 74143, 74509, 74874, 75239, 75604, 75970, 76335, 76700, 77065, 77431, 77796, 78161, 78526, 78892, 79257, 79622, 79987, 80353, 80718, 81083, 81448, 81814, 82179, 82544, 82909, 83275, 83640, 84005, 84370, 84736, 85101, 85466, 85831, 86197, 86562, 86927, 87292, 87658, 88023, 88388, 88753, 89119, 89484, 89849, 90214, 90580, 90945, 91310, 91675, 92041, 92406, 92771, 93136, 93502, 93867, 94232, 94597, 94963, 95328, 95693, 96058, 96424, 96789, 97154, 97519, 97885, 98250, 98615, 98980, 99346, 99711, 100076, 100441, 100807, 101172, 101537, 101902, 102268, 102633, 102998, 103363, 103729, 104094, 104459, 104824, 105190, 105555, 105920, 106285, 106651, 107016, 107381, 107746, 108112, 108477, 108842, 109207, 109572, 109937, 110302, 110667, 111033, 111398, 111763, 112128, 112494, 112859, 113224, 113589, 113955, 114320, 114685, 115050, 115416, 115781, 116146, 116511, 116877, 117242, 117607, 117972, 118338, 118703, 119068, 119433, 119799, 120164, 120529, 120894, 121260, 121625, 121990, 122355, 122721, 123086, 123451, 123816, 124182, 124547, 124912, 125277, 125643, 126008, 126373, 126738, 127104, 127469, 127834, 128199, 128565, 128930, 129295, 129660, 130026, 130391, 130756, 131121, 131487, 131852, 132217, 132582, 132948, 133313, 133678, 134043, 134409, 134774, 135139, 135504, 135870, 136235, 136600, 136965, 137331, 137696, 138061, 138426, 138792, 139157, 139522, 139887, 140253, 140618, 140983, 141348, 141714, 142079, 142444, 142809, 143175, 143540, 143905, 144270, 144636, 145001, 145366, 145731, 146097};
inline large_type read() {
large_type sum = 0, f = 1;
char c = getchar();

while (c < '0' || c > '9') {
if (c == '-')
f = -1;

c = getchar();
}

while (c >= '0' && c <= '9') {
sum = sum * 10 + c - '0';
c = getchar();
}

return sum * f;
}

inline void print(large_type x) {
char f[200];
large_type tmp = x > 0 ? x : -x;

if (x < 0) {
putchar('-');
}

int cnt = 0;

while (tmp > 0) {
f[cnt++] = tmp % 10 + '0';
tmp /= 10;
}

while (cnt > 0) {
putchar(f[--cnt]);
}
}

inline void output(bool bc, int day, int month, large_type year) {
print(day);
putchar(' ');
print(month);
putchar(' ');
print(year);

if (bc) {
putchar(' ');
putchar('B');
putchar('C');
}

putchar('\n');
}

inline int mod(large_type a, int p) {
if (p == 0) {
return a;
}

return a % p;
}

inline void process(large_type t) {
int day, month, day_of_year = 0;
large_type year;
bool bc = t <= 0, leap = false;

if (bc) {
t = -t;
year = t * 4 / 1461;
leap = year % 4 == 0;
day_of_year = (year + 1) * 1461 / 4 - t;

if (leap || year % 4 == 1 || year % 4 == 2) {
day_of_year++;
}

year++;

} else if (t < 584391) {
if (t >= 577738) {
t += 10;
}

year = t * 4 / 1461;

if (year * 1461 == t * 4) {
year = (t - 1) * 4 / 1461;
}

leap = (year + 1) % 4 == 0;
day_of_year = t - year++ * 1461 / 4;

} else {
t -= 2;
year = t / 146097 * 400;
int day_of_400_years = t % 146097;

if (day_of_400_years == 0) {
day_of_400_years = 146097;
year -= 400;
}

for (int i = 1; i <= 400; i++) {
if (dty[i] < day_of_400_years && day_of_400_years <= dty[i + 1]) {
year += i;
day_of_year = day_of_400_years - dty[i];
break;
}
}

leap = year % 400 == 0 || (year % 100 != 0 && year % 4 == 0);
}

month = doytm[day_of_year][leap];
day = mod(day_of_year, mtdoy[month - 1][leap]);
output(bc, day, month, year);
}

int main() {
q = read();

while (q--) {
day = -1721423;
r = read();
day += r;
process(day);
}

return 0;
}
骗你的,这代码在一本通直接过不了编译
  • 标题: CSP-S 2020 儒略日切后感
  • 作者: Phizo
  • 创建于 : 2021-11-16 10:37:55
  • 更新于 : 2024-10-23 10:16:01
  • 链接: https://phizone.cn/2021/11/16/oi-p7075/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。