CSP-S 2020 题解

儒略日

分析

将时间分成 公元前、1.1.14.10.158215.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

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值