儒略日
分析
将时间分成 公元前、1.1.1
到 4.10.1582
、 15.10.1582
以后 三段分别处理即可,没有太大思维难度。
实现较繁琐,具体看代码。
代码
// 代码中的各个常数用计算器或写个程序就能很快算出,不再赘述
#include <iostream>
#include <cstdio>
using namespace std;
int q,t[13] = {
0,31,28,31,30,31,30,31,31,30,31,30,31};
long long n;
long long read(){
long long x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
void work(int &d,int &m,int n,int p = 0){
// 算出 1.1 向后 n 天的日期并存在 d,m 中,需保证结果在同一年中
// p=1/0 表示 是/否 是闰年
// t 表示平年中每个月的天数
if(p) t[2] = 29;//闰年 2 月有 29 天
for(int i = 1; i <= 12; i ++){
if(n >= t[i]) n -= t[i],m ++;
else{
d += n,t[2] = 28;// 将 t[2] 复原
return;
}
}
}
void solve1(){
// 1461 = 3*365 + 366
int d = 1,m = 1,y = -4713;
y += n / 1461 * 4,n %= 1461;// 四年四年跳
if(n < 366) work(d,m,n,1);// 闰年
else{
// 平年
n -= 366,y ++;
y += n / 365,n %= 365;
work(d,m,n);
}
printf("%d %d %d BC\n",d,m,-y);
}
void solve2(){
int d = 1,m = 1,y = 1;
n -= 1721424;// 跳到 1.1.1 并减去相应日期
y += n / 1461 * 4,n %= 1461;// 四年四年跳
// 1095 = 3*365
if(n < 1095){
// 平年
y += n / 365,n %= 365;
work(d,m,n);
}else{
// 闰年
n -= 1095,y += 3;
work(d,m,n,1);
}
printf("%d %d %d\n",d,m,y);
}
void solve3(){
int d = 15,m = 10,y = 1582;
n -= 2299161;// 跳到 15.10.1582 并减去相应日期
if(n <= 77){
// 答案在 1582 年中,直接计算
if(n <= 16) printf("%d %d %d\n",d + n,m,y);
else if(n <= 46) printf("%d %d %d\n",n - 16,m + 1,y);
else printf("%d %d %d\n",n - 46,m + 2,y);
return;
}
n -= 78,d = 1,m = 1,y = 1583;// 跳到 1.1.1583
// 146097 = 303*365 + 97*366
y += n / 146097 * 400,n %= 146097;// 四百年四百年跳
// 由于 1583 % 400 = 383,下面按照答案年份模 400 分为 383 ~ 399、0、1 ~ 382 三段
if(n < 6209){
// 383 ~ 399
// 6209 = 13*365 + 4*366
y += n / 1461 * 4,n %= 1461;// 四年四年跳
if(n < 365) work(d,m,n);
else if(n < 731){
n -= 365,y ++;
work(d,m,n,1);
}else{
n -= 731,y += 2;
y += n / 365,n %= 365;
work(d,m,n);
}
printf("%d %d %d\n",d,m,y);
}else if(n < 6575){
// 0
// 6575 = 13*365 + 5*366
n -= 6209,d = 1,m = 1,y += 17;
work(d,m,n,1);
printf("%d %d %d\n",d,m,y);
}else{
// 1 ~ 382
n -= 6575,d = 1,m = 1,y += 18;
y += n / 36524 * 100,n %= 36524;// 一百一百年跳
// 36159 = 75*365 + 24*366
if(n < 36159){
// 前99年
y += n / 1461 * 4,n %= 1461;// 四年四年跳
if(n < 1095){
y += n / 365,n %= 365;
work(d,m,n);
}else{
n -= 1095,y += 3;
work(d,m,n,1);
}
}else{
// 整百年
n -= 36159,y += 99;
work(d,m,n);
}
printf("%d %d %d\n",d,m,y);
}
}
int main(){
// freopen("julian.in","r",stdin);
// freopen("julian.out","w",stdout);
q = read();
while(q --){
n = read();
if(n <= 1721423) solve1();// 公元前
else if(n <= 2299160) solve2();// 1.1.1 ~ 4.10.1582
else solve3();// 15.10.1582+
}
return 0;
}
动物园
分析
通读题目后可以发现饲料就是个障眼法,我们能取的位就是原有的位与没有饲料限制的位(因为题目保证 q i q_i qi 互不相同)。
故设 t t t 表示上述能取的位的个数,则所有符合条件的编号个数就是 2 t 2^t 2t。而我们已经有了 n n n 个编号且题目保证了它们互不相同,所以答案就是 2 t − n 2^t - n