题解 | 桂林学院2023年天梯赛省赛热身赛

题解 | 桂林学院2023年天梯赛省赛热身赛图片引用自CDN加速图床 https://cdnjson.com/


L1-1 今天我要赢

题目

2018 年我们曾经出过一题,是输出“2018 我们要赢”。今年是 2022 年,你要输出的句子变成了“我要赢!就在今天!”然后以比赛当天的日期落款。

输入格式:
本题没有输入。

输出格式:
输出分 2 行。在第一行中输出 I'm gonna win! Today!,在第二行中用 年年年年-月月-日日 的格式输出比赛当天的日期。已知比赛的前一天是 2022-04-22。

输入样例:
无
输出样例(第二行的内容要你自己想一想,这里不给出):
I'm gonna win! Today!
这一行的内容我不告诉你…… 你要自己输出正确的日期呀~

思路

直接输出,日期加一天就行

参考代码(c语言)

#include<stdio.h>
int main()
{
	printf("I'm gonna win! Today!\n2022-04-23");
}

参考代码(c++)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	cout<<"I'm gonna win! Today!"<<endl<<"2022-04-23";
}

L1-2 种钻石

题目

2019年10月29日,中央电视台专题报道,中国科学院在培育钻石领域,取得科技突破。科学家们用金刚石的籽晶片作为种子,利用甲烷气体在能量作用下形成碳的等离子体,慢慢地沉积到钻石种子上,一周“种”出了一颗 1 克拉大小的钻石。

本题给出钻石的需求量和人工培育钻石的速度,请你计算出货需要的时间。

输入格式:
输入在一行中给出钻石的需求量 N(不超过 10^7 的正整数,以微克拉为单位)和人工培育钻石的速度 v(1≤v≤200,以微克拉/天为单位的整数)。

输出格式:
在一行中输出培育 N 微克拉钻石需要的整数天数。不到一天的时间不算在内。

输入样例:
102000 130
输出样例:
784

思路

两数相除即可

参考代码(c语言)

#include<stdio.h>
int main()
{
	int a,sum=0;
	cin>>a;
	sum=a/100+a/10%10+a%10;
	printf("%d的3个数字之和是%d",a,sum);
}

参考代码(c++)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,m;
	cin>>n>>m;
	cout<<n/m;
}

L1-3 谁能进图书馆

题目

为了保障安静的阅读环境,有些公共图书馆对儿童入馆做出了限制。例如“12 岁以下儿童禁止入馆,除非有 18 岁以上(包括 18 岁)的成人陪同”。现在有两位小/大朋友跑来问你,他们能不能进去?请你写个程序自动给他们一个回复。

输入格式:
输入在一行中给出 4 个整数:

禁入年龄线 陪同年龄线 询问者1的年龄 询问者2的年龄
这里的禁入年龄线是指严格小于该年龄的儿童禁止入馆;陪同年龄线是指大于等于该年龄的人士可以陪同儿童入馆。默认两个询问者的编号依次分别为 1 和 2;年龄和年龄线都是 [1, 200] 区间内的整数,并且保证 陪同年龄线 严格大于 禁入年龄线。

输出格式:
在一行中输出对两位询问者的回答,如果可以进就输出 年龄-Y,否则输出 年龄-N,中间空 1 格,行首尾不得有多余空格。

在第二行根据两个询问者的情况输出一句话:

如果两个人必须一起进,则输出 qing X zhao gu hao Y,其中 X 是陪同人的编号, Y 是小孩子的编号;
如果两个人都可以进但不是必须一起的,则输出 huan ying ru guan;
如果两个人都进不去,则输出 zhang da zai lai ba;
如果一个人能进一个不能,则输出 X: huan ying ru guan,其中 X 是可以入馆的那个人的编号。

输入样例 1:
12 18 18 8
输出样例 1:
18-Y 8-Y
qing 1 zhao gu hao 2
输入样例 2:
12 18 10 15
输出样例 2:
10-N 15-Y
2: huan ying ru guan

思路

对几种情况进行判断,注意边界就行

参考代码(c++)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b,c,d;
	cin>>a>>b>>c>>d;
	if(c<a&&d<a){
		cout<<c<<"-N "<<d<<"-N"<<endl;
		cout<<"zhang da zai lai ba";
	}else if(c>=a&&d>=a){
		cout<<c<<"-Y "<<d<<"-Y"<<endl;
		cout<<"huan ying ru guan";
	}else if((c<a&&d>=b)||(d<a&&c>=b)){
		cout<<c<<"-Y "<<d<<"-Y"<<endl;
		if(c>d){
			cout<<"qing 1 zhao gu hao 2";
		}else{
			cout<<"qing 2 zhao gu hao 1";
		}	
	}else if((c<a&&d>a&&d<b)||(d<a&&c>a&&c<b)){
		if(c>d){
			cout<<c<<"-Y "<<d<<"-N"<<endl;
			cout<<"1: huan ying ru guan";
		}else{
			cout<<c<<"-N "<<d<<"-Y"<<endl;
			cout<<"2: huan ying ru guan";
		}
	}
}

L1-4 拯救外星人

题目

你的外星人朋友不认得地球上的加减乘除符号,但是会算阶乘 —— 正整数 N 的阶乘记为 “N!”,是从 1 到 N 的连乘积。所以当他不知道“5+7”等于多少时,如果你告诉他等于“12!”,他就写出了“479001600”这个答案。

本题就请你写程序模仿外星人的行为。

输入格式:
输入在一行中给出两个正整数 A 和 B。

输出格式:
在一行中输出 (A+B) 的阶乘。题目保证 (A+B) 的值小于 12。

输入样例:
3 6
输出样例:
362880

思路

先计算a+b,再用一个循环计算阶乘

参考代码(c语言)

#include<stdio.h>
int main()
{
	int a,b;
	long long int res=1;
	scanf("%d %d",&a,&b);
	a+=b;
	for(int i=1;i<=a;i++){
		res*=i;
	}
	printf("%d",res);
}

参考代码(c++)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long int a,b,res=1;
	cin>>a>>b;
	a+=b;
	for(int i=1;i<=a;i++){
		res*=i;
	}
	cout<<res;
}

L1-5 试试手气

题目

我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:

1、每个骰子摇出的点数都跟它之前任何一次出现的点数不同;
2、在满足条件 1 的前提下,每次都能让每个骰子得到可能得到的最大点数。
那么你应该可以预知自己第 n 次(1≤n≤5)摇出的结果。

输入格式:
输入第一行给出 6 个骰子的初始点数,即 [1,6] 之间的整数,数字间以空格分隔;第二行给出摇的次数 n(1≤n≤5)。

输出格式:
在一行中顺序列出第 n 次摇出的每个骰子的点数。数字间必须以 1 个空格分隔,行首位不得有多余空格。

输入样例:
3 6 5 4 1 4
3
输出样例:
4 3 3 3 4 3
样例解释:
这 3 次摇出的结果依次为:

6 5 6 6 6 6
5 4 4 5 5 5
4 3 3 3 4 3

思路

网上思路大都双循环,但是单循环就行了

判断从6到6-n时会不会碰到初始点数。未碰到,则输出;碰到了,就跳过,再输出结果。

参考代码(c语言)

#include<stdio.h>
int main()
{
	int n,a[7]={0};
	for (int i = 1; i <= 6; i++) scanf("%d",&a[i]);;
	scanf("%d",&n);
	for(int i = 1; i <= 6; i++){
        printf("%d",a[i]>6-n?6-n:6-n+1);
        if(i!=6) printf(" ");
	}
}

参考代码(c++)

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,a[7]={0};
	for (int i = 1; i <= 6; i++) cin>>a[i];
	cin>>n;
	for(int i = 1; i <= 6; i++){
		int c = a[i]>6-n?6-n:6-n+1;
        cout<<c;
        if(i!=6) cout<<" ";
	}
}

L1-6 斯德哥尔摩火车上的题

题目

上图是新浪微博上的一则趣闻,是瑞典斯德哥尔摩火车上的一道题,看上去是段伪代码:

s = ''
a = '1112031584'
for (i = 1; i < length(a); i++) {
  if (a[i] % 2 == a[i-1] % 2) {
    s += max(a[i], a[i-1])
  }
}
goto_url('www.multisoft.se/' + s)
其中字符串的 + 操作是连接两个字符串的意思。所以这道题其实是让大家访问网站 www.multisoft.se/112358(注意:比赛中千万不要访问这个网址!!!)。

当然,能通过上述算法得到 112358 的原始字符串 a 是不唯一的。本题就请你判断,两个给定的原始字符串,能否通过上述算法得到相同的输出?

输入格式:
输入为两行仅由数字组成的非空字符串,长度均不超过 10^4 ,以回车结束。

输出格式:
对两个字符串分别采用上述斯德哥尔摩火车上的算法进行处理。如果两个结果是一样的,则在一行中输出那个结果;否则分别输出各自对应的处理结果,每个占一行。题目保证输出结果不为空。

输入样例 1:
1112031584
011102315849
输出样例 1:
112358
输入样例 2:
111203158412334
12341112031584
输出样例 2:
1123583
112358

思路

字符串处理

按照伪代码的思路遍历处理字符串,将处理后的结果存到两个新字符串中再对比判断输出即可

参考代码(c++)

#include <bits/stdc++.h>
using namespace std;

int main() {
	string a, b,s1,s2;
	cin >> a >> b;
	for (int i = 1; i < a.size(); i++) {
		if (a[i] % 2 == a[i - 1] % 2) {
			s1+= max(a[i], a[i - 1]);
		}
	}
	for (int i = 1; i < b.size(); i++) {
		if (b[i] % 2 == b[i - 1] % 2) {
			s2+= max(b[i], b[i - 1]);
		}
	}
	cout<<s1;
	if(s1!=s2){
		cout<<endl<<s2;
	}
   	return 0;
}

L1-7 机工士姆斯塔迪奥

题目

在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。

你需要处理这个副本其中的一个机制:N×M 大小的地图被拆分为了 N×M 个 1×1 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家不能站在释放技能的方格上,否则就会被击中而失败。

给定 BOSS 所有释放技能的行或列信息,请你计算出最后有多少个格子是安全的。

输入格式:
输入第一行是三个整数 N,M,Q (1≤N×M≤10^5,0≤Q≤1000),表示地图为 N 行 M 列大小以及选择的行/列数量。

接下来 Q 行,每行两个数 T i,C i,其中 T i =0 表示 BOSS 选择的是一整行,T i =1 表示选择的是一整列,C i为选择的行号/列号。行和列的编号均从 1 开始。

输出格式:
输出一个数,表示安全格子的数量。

输入样例:
5 5 3
0 2
0 4
1 3
输出样例:
12

思路

去掉技能释放的那一行/列

统计最终的行和列的数量,相乘就行。

可以使用set集合处理,自动去重。

参考代码(c++) 数组处理

#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long int n,m,q,t,c;
	cin>>n>>m>>q;
	int row[n+1]={0},column[m+1]={0};
	while (q--) {
		cin>>t>>c;
		if(t==0){
			if(row[c]==0){
				row[c]=1;
				n--;
			}
		}else{
			if(column[c]==0){
				column[c]=1;
				m--;
			}
		}
	}
    cout<<n*m;
	return 0;
}

参考代码(c++) set集合处理

#include<bits/stdc++.h>
using namespace std;
set<int>a,b;
int main(){
    int n,m,q,t,c;
    cin>>n>>m>>q;
    while(q--){
        cin>>t>>c;
        if(t==0) a.insert(c);
        else b.insert(c);
    }
    cout<<(n-a.size())*(m-b.size());
}

L1-8 静静的推荐

题目

天梯赛结束后,某企业的人力资源部希望组委会能推荐一批优秀的学生,这个整理推荐名单的任务就由静静姐负责。企业接受推荐的流程是这样的:

只考虑得分不低于 175 分的学生;
一共接受 K 批次的推荐名单;
同一批推荐名单上的学生的成绩原则上应严格递增;
如果有的学生天梯赛成绩虽然与前一个人相同,但其参加过 PAT 考试,且成绩达到了该企业的面试分数线,则也可以接受。
给定全体参赛学生的成绩和他们的 PAT 考试成绩,请你帮静静姐算一算,她最多能向企业推荐多少学生?

输入格式:
输入第一行给出 3 个正整数:N(≤10 ^5 )为参赛学生人数,K(≤5×10^3 )为企业接受的推荐批次,S(≤100)为该企业的 PAT 面试分数线。

随后 N 行,每行给出两个分数,依次为一位学生的天梯赛分数(最高分 290)和 PAT 分数(最高分 100)。

输出格式:
在一行中输出静静姐最多能向企业推荐的学生人数。

输入样例:
10 2 90
203 0
169 91
175 88
175 0
175 90
189 0
189 0
189 95
189 89
256 100
输出样例:
8
样例解释:
第一批可以选择 175、189、203、256 这四个分数的学生各一名,此外 175 分 PAT 分数达到 90 分的学生和 189 分 PAT 分数达到 95 分的学生可以额外进入名单。第二批就只剩下 175、189 两个分数的学生各一名可以进入名单了。最终一共 8 人进入推荐名单。

思路

天梯赛分数小于175不用考虑

天梯赛分数大于等于175且pat分数大于面试分数S则可以无视批次,直接录取。

其他的按照同一分数只能录取k个人进行录取

参考代码(c++)

#include <bits/stdc++.h>
using namespace std;

int main() {
	int n, k, s, a[292] = {0}, ans = 0;
	cin >> n >> k >> s;
	while (n--) {
		int t, p;
		cin >> t >> p;
		if (t >= 175) {
			if (p >= s) {
				ans++;
			} else {
                if(a[t]<k){
                    ans++;
                    a[t]++;
                }
			}
		}
	}
    cout << ans;
	return 0;
}

L2-2 老板的作息表

题目

新浪微博上有人发了某老板的作息时间表,表示其每天 4:30 就起床了。但立刻有眼尖的网友问:这时间表不完整啊,早上九点到下午一点干啥了?

本题就请你编写程序,检查任意一张时间表,找出其中没写出来的时间段。

输入格式:
输入第一行给出一个正整数 N,为作息表上列出的时间段的个数。随后 N 行,每行给出一个时间段,格式为:

hh:mm:ss - hh:mm:ss
其中 hh、mm、ss 分别是两位数表示的小时、分钟、秒。第一个时间是开始时间,第二个是结束时间。题目保证所有时间都在一天之内(即从 00:00:00 到 23:59:59);每个区间间隔至少 1 秒;并且任意两个给出的时间区间最多只在一个端点有重合,没有区间重叠的情况。

输出格式:
按照时间顺序列出时间表中没有出现的区间,每个区间占一行,格式与输入相同。题目保证至少存在一个区间需要输出。

输入样例:
8
13:00:00 - 18:00:00
00:00:00 - 01:00:05
08:00:00 - 09:00:00
07:10:59 - 08:00:00
01:00:05 - 04:30:00
06:30:00 - 07:10:58
05:30:00 - 06:30:00
18:00:00 - 19:00:00
输出样例:
04:30:00 - 05:30:00
07:10:58 - 07:10:59
09:00:00 - 13:00:00
19:00:00 - 23:59:59

思路

将一天的开始时间记为"00:00:00";结束时间记为"23:59:59"。

把每段的开始时间和结束时间放入结构体,对结构体进行排序。

对比上一段的结束时间是否等于当前的开始时间。如果是,则时间连续;反之,时间不连续,输出上一段的结束时间和当前的开始时间。

参考代码(c++)

#include <bits/stdc++.h>
using namespace std;
// 定义结构体,用来存每个时间段(开始时间和结束时间)
struct node {
	string begin, end;
} s[100001];
// 自定义结构体排序,按开始时间进行排序
bool cmp(node &a, node &b) {
	return b.begin > a.begin;
}

int main() {
	int n;
	char c;
	string b = "00:00:00", e = "23:59:59";   // 一天的开始时间和结束时间
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> s[i].begin >> c >> s[i].end;
	}
	sort(s, s + n, cmp);
	for (int i = 0; i < n; i++) {
		if (b != s[i].begin) // 对比上一段的结束时间是否等于当前的开始时间
			cout << b << " - " << s[i].begin << endl;
		b = s[i].end;
	}
	if (b != e)
		cout << b << " - " << e;
	return 0;
}


L2-3 龙龙送外卖

题目

龙龙是“饱了呀”外卖软件的注册骑手,负责送帕特小区的外卖。帕特小区的构造非常特别,都是双向道路且没有构成环 —— 你可以简单地认为小区的路构成了一棵树,根结点是外卖站,树上的结点就是要送餐的地址。

每到中午 12 点,帕特小区就进入了点餐高峰。一开始,只有一两个地方点外卖,龙龙简单就送好了;但随着大数据的分析,龙龙被派了更多的单子,也就送得越来越累……

看着一大堆订单,龙龙想知道,从外卖站出发,访问所有点了外卖的地方至少一次(这样才能把外卖送到)所需的最短路程的距离到底是多少?每次新增一个点外卖的地址,他就想估算一遍整体工作量,这样他就可以搞明白新增一个地址给他带来了多少负担。

输入格式:
输入第一行是两个数 N 和 M (2≤N≤10^5 , 1≤M≤10^5 ),分别对应树上节点的个数(包括外卖站),以及新增的送餐地址的个数。

接下来首先是一行 N 个数,第 i 个数表示第 i 个点的双亲节点的编号。节点编号从 1 到 N,外卖站的双亲编号定义为 −1。

接下来有 M 行,每行给出一个新增的送餐地点的编号 X i 。保证送餐地点中不会有外卖站,但地点有可能会重复。

为了方便计算,我们可以假设龙龙一开始一个地址的外卖都不用送,两个相邻的地点之间的路径长度统一设为 1,且从外卖站出发可以访问到所有地点。

注意:所有送餐地址可以按任意顺序访问,且完成送餐后无需返回外卖站。

输出格式:
对于每个新增的地点,在一行内输出题目需要求的最短路程的距离。

输入样例:
7 4
-1 1 1 1 2 2 3
5
6
2
4
输出样例:
2
4
4
6

思路

要走完所有节点,那么从根节点到当前节点的每条边都需要遍历

但题目要求最后不需要返回跟节点,只需留在最后一个节点位置就行

结果 = 总长度 - 最深的节点深度

使用 DFS(深度优先搜索)实现

参考代码(c++)

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int dis[N], p[N];// dis数组记录每个节点距离根节点长度  p数组记录每个节点的父节点
int sum = 0;
// 定义dfs函数,遍历树
int dfs(int u) {
	if (p[u] == -1 || dis[u] > 0)
		return dis[u];
	sum++;
	dis[u] = dfs(p[u]) + 1;
	return dis[u];
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> p[i];
	int mx = 0, d;
	while (m -- ) {
		cin >> d;
		mx = max(dfs(d), mx); //记录走过点的最深层
		cout << sum * 2 - mx << endl; //全部的路减去最远的路
	}
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值