团队天梯赛练习题题解 L1-001~L1-010

前情提要,Python题解思路基本写在代码,新老博客夹杂写出的,风格不统一也正常
两个人思路不一样也很正常,两种思路都可以的,不一定只有这种实现

L1-001 Hello World (5 分)

这道超级简单的题目没有任何输入。

你只需要在一行中输出著名短句Hello World!就可以了。

输入样例

输出样例

Hello World!

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ の C++ 解決策

#include<cstdio>
int main()
{
	printf("Hello World!");
	return 0;
}

winterl の Python 解決策

# 尽量直接复制粘贴,避免手贱,眼花,打错带来的错误
print("Hello World!")

L1-002 打印沙漏 (20 分)

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个*,要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差22;符号数先从大到小顺序递减到11,再从小到大顺序递增;首尾符号数相等。

给定任意NN个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式

输入在一行给出11个正整数N(1000)N(\leqslant 1000)和一个符号,中间以空格分隔。

输出格式

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例

19 *

输出样例

*****
 ***
  *
 ***
*****

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ’s Solution

  1. 设定变量maxs为第一行需要输出的、最大的 符号数;

  2. 遍历寻找maxs的最大值,对于总的符号数,有公式(1+maxs)(maxs2+1)221\frac{(1+maxs)*(\lfloor\frac{maxs}{2}\rfloor+1)}{2}*2-1

公式左边为等差数列求和,21*2-1是因为要组成沙漏,可以看成上下镜像后将其中一个*去掉即可;

  1. 对于空格数量,设当前行需要输出字符数量为j,则需要输出的空格数量为maxsj2\lfloor\frac{maxs-j}{2}\rfloor

  2. 对于剩余符号数,即n(1+maxs)(maxs2+1)221n-\frac{(1+maxs)*(\lfloor\frac{maxs}{2}\rfloor+1)}{2}*2-1

PotremZ の C++ 解決策

#include<cstdio>
int main()
{
	int n,maxs=1; char ch; scanf("%d %c",&n,&ch);
	for(;;maxs+=2){
		if(n<(1+(maxs+2))*((maxs+2)/2+1)-1) break;
	}
	for(int i=maxs;i>=1;i-=2){
		for(int j=1;j<=(maxs-i)/2;++j) printf(" ");
		for(int k=1;k<=i;++k) printf("%c",ch);
		puts("");
	}
	for(int i=3;i<=maxs;i+=2){
		for(int j=1;j<=(maxs-i)/2;++j) printf(" ");
		for(int k=1;k<=i;++k) printf("%c",ch);
		puts("");
	}
	printf("%d",n-((1+maxs)*(maxs/2+1)-1));
	return 0;
}

winterl の Python 解決策

n, symbol = input().split()
count = int(n)
# 暴力枚举,求出剩下多少,这里也可以用数学公式推
used = 1
max_width = 1
while used <= count:
    max_width += 2
    used += max_width * 2
used -= max_width * 2
max_width -= 2
# 计算出剩下多少个,和顶层有多少个
unused = count - used
current_width = max_width
# 打印一层
def show_line(current_width): 
    space = " " * ((max_width - current_width) // 2)
    symbols = symbol * current_width 
    print(space + symbols)
# 打印沙漏
while current_width > 1:
    show_line(current_width)
    current_width -= 2
while current_width <= max_width:
    show_line(current_width)
    current_width += 2
# 打印剩余
print(unused)

L1-003 个位数统计 (15 分)

给定一个 kk 位整数 N=dk110k1++d1101+d0(0di9,i=0,,k1,dk1>0)N=d_{k−1}10^{k−1}+⋯+d_{1}10^1+d_0(0 \leqslant d_i \leqslant 9, i=0,⋯,k−1, d_{k−1}>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311N=100311,则有 22003311,和 1133

输入格式

每个输入包含 11 个测试用例,即一个不超过 10001000 位的正整数 NN

输出格式

NN 中每一种不同的个位数字,以 D:MD:M 的格式在一行中输出该位数字 DD 及其在 NN 中出现的次数 MM。要求按 DD 的升序输出。

输入样例

100311

输出样例

0:2
1:3
3:1

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ’s Solution

  1. 因为NN的位数很大,而且只关注每位上是什么数字,故将NN作为string读入;

  2. 随后记录数字出现次数即可;

PotremZ の C++ 解決策

#include<iostream>
using namespace std;
int num[10];
int main()
{
	string n; cin>>n;
	for(int i=0;i<n.size();++i)
		++num[n[i]-'0'];
	for(int i=0;i<=9;++i)
		if(num[i]) cout<<i<<":"<<num[i]<<endl;
	return 0;
}

winterl の Python 解決策

number = input()
# 这里在别的语言可以用SortedMap来秒
# 但是Python的字典是无序的,做不到
# 所以需要用离散化的方法
values = list(number)
values.sort()
# 方便处理末尾情况
values.append("")

counter = 0
last_value = values[0]
answer_lines = []
# 扫一遍数字,直接统计就好
for value in values:
    if last_value == value:
        counter += 1
        continue
    # elif last_value == -1 or last_value != value
    answer_lines.append(f"{last_value}:{counter}")
    last_value = value
    counter = 1

print("\n".join(answer_lines))

L1-004 计算摄氏温度 (5 分)

给定一个华氏温度FF,本题要求编写程序,计算对应的摄氏温度CC。计算公式:C=5×(F32)/9C=5×(F−32)/9。题目保证输入与输出均在整型范围内。

输入格式

输入在一行中给出一个华氏温度。

输出格式

在一行中按照格式Celsius = C输出对应的摄氏温度CC的整数值。

输入样例

150

输出样例

Celsius = 65

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ の C++ 解決策

#include<cstdio>
int main(){
	int F; scanf("%d",&F);
	printf("Celsius = %d",5*(F-32)/9);
	return 0;
}

winterl の Python 解決策

F = int(input())
# 这里是一个神坑,如果用//整除,可能出现结果不对
# 但是除后转成整数就可以对。原因是负数除法的处理不同
# 如 31,整除会向下取整,取 -1,而转换 int 只会保留整数位
print(f"Celsius = {int(5 * (F - 32) / 9)}")

L1-005 考试座位号 (15 分)

每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位。正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试座位就座。但有些考生迟到了,试机已经结束,他们只能拿着领到的试机座位号码求助于你,从后台查出他们的考试座位号码。

输入格式

输入第一行给出一个正整数 N(1000)N(\leqslant 1000),随后 NN 行,每行给出一个考生的信息:准考证号 试机座位号 考试座位号。其中准考证号由 1616 位数字组成,座位从 11NN 编号。输入保证每个人的准考证号都不同,并且任何时候都不会把两个人分配到同一个座位上。

考生信息之后,给出一个正整数 M(N)M( \leqslant N),随后一行中给出 MM 个待查询的试机座位号码,以空格分隔。

输出格式

对应每个需要查询的试机座位号码,在一行中输出对应考生的准考证号和考试座位号码,中间用 11 个空格分隔。

输入样例

4
3310120150912233 2 4
3310120150912119 4 1
3310120150912126 1 3
3310120150912002 3 2
2
3 4

输出样例

3310120150912002 2
3310120150912119 1

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:200 ms
内存限制:64 MB

PotremZ’s Solution

  1. 直接使用STL中的map,设每个学生有一个学生序号i(1in)i(1\leqslant i \leqslant n)

  2. map让每个试机座位号都对应一个学生序号,每次寻找直接输出对应学生序号下的准考证号和考试座位号即可;

PotremZ の C++ 解決策

#include<cstdio>
#include<map>
using namespace std;
const int N=1010;
map<int,int>mp;
long long zhun_kao[N];
int shi_ji[N],kao_shi[N];
int main(){
	int n; scanf("%d",&n);
	while(n--){
		scanf("%lld %d %d",&zhun_kao[n],&shi_ji[n],&kao_shi[n]);
		mp[shi_ji[n]]=n;
	}
	int m; scanf("%d",&m);
	while(m--){
		int Shi_Ji; scanf("%d",&Shi_Ji);
		printf("%lld %d\n",zhun_kao[mp[Shi_Ji]],kao_shi[mp[Shi_Ji]]);
	}
	return 0;
}

winterl の Python 解決策

# 容易想到,用一个字典
# 键为查询用的 试机座位号
# 值为 准考证号 和 考试座位号 的元组
machine_table = {}
for _ in range(int(input())):
    student_id, machine_id, exam_id = map(int, input().split())
    machine_table[machine_id] = (student_id, exam_id)
_ = input() # 可以忽略这一行,不需要这个信息,也可用它来辅助输入
for query_id in map(int, input().split()):
    # 每次查询,直接利用字典查就好了
    student_id, exam_id = machine_table[query_id]
    print(student_id, exam_id)

L1-006 连续因子 (20 分)

一个正整数 NN 的因子中可能存在若干连续的数字。例如 630630 可以分解为 3×5×6×73×5×6×7,其中 5675、6、7 就是 33 个连续的数字。给定任一正整数 NN,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

输入格式

输入在一行中给出一个正整数 N(1<N<231)N(1<N<2^{31})

输出格式

首先在第 11 行输出最长连续因子的个数;然后在第 22 行中按 因子1*因子2*……*因子k 的格式输出最小的连续因子序列,其中因子按递增顺序输出,11 不算在内。

输入样例

630

输出样例

3
5*6*7

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ’s Solution

思路来自林夕-梦的天梯赛 L1-006 连续因子 (模拟)

一开始读错题了,以为是要找约数,一个最大连续、一个最小连续
但实际上,就是单纯让分解NN,求出一个最长连续因子个数,并输出其字典序最小序列;

  1. 因为需要分解NN,考虑到231=2,147,483,648<13!=6,227,020,8002^{31}=2,147,483,648<13!=6,227,020,800,且题目要求不考虑11,则序列最长长度即为1111

首先它到不了13,所以最大为12!12!,又忽略11,故为1111

  1. 让序列从最长开始遍历,让因子从22遍历到N\sqrt N,并按照序列长度累乘(因为如果序列中有数 >N>\sqrt N,则可能有N×N+1>N\sqrt N \times \sqrt{N+1} >N,显然非法);

  2. 这样,当找到一组合法解时,此解必然为最长序列,且其字典序最小;

PotremZ の C++ 解決策

#include<cstdio>
#define ll long long
int main(){
	int n; scanf("%d",&n);
	for(int len=11;len>=1;--len){
		for(ll i=2;i*i<=n;++i){
			ll res=1;
			for(int j=i;j<=i+len-1;++j){
				res*=j;
				if(res>n) break;
			}
			if(n%res==0){
				printf("%d\n",len);
				for(int j=i;j<=i+len-1;++j)
					printf("%d%c",j,j==i+len-1? 0 : '*');
				return 0;
			}
		}
	}
	printf("1\n%d",n);
	return 0;
}

winterl の Python 解決策

n = int(input())

# 朴素分解因子的时间复杂度是 O(n)
# 数据范围比较大,应该采用一个小于 O(n) 的算法
# 可以采用开根优化来分解因子

# 求从 start 开始的连续因子列表
def get_lined_factors(start):
    num = n
    result = []
    current = start
    while num % current == 0:
        num //= current
        # 用字符串是为了方便后续的输出
        result.append(str(current))
        current += 1
    return result

answer = []
# 枚举每个因子起点
for start in range(2, int(n ** 0.5) + 1):
    factors = get_lined_factors(start)
    if len(factors) > len(answer):
        answer = factors

# 是素数(质数)的情况
length = len(answer)
if length == 0:
    print(1)
    print(n)
else:
    print(length)
    print("*".join(answer))

L1-007 念数字 (10 分)

输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu字。十个数字对应的拼音如下:

0: ling
1: yi
2: er
3: san
4: si
5: wu
6: liu
7: qi
8: ba
9: jiu

输入格式

输入在一行中给出一个整数,如:1234

提示:整数包括负数、零和正数。

输出格式

在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如 yi er san si

输入样例

-600

输出样例

fu liu ling ling

作者:翁恺
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ’s Solution

  1. 使用map预处理对应拼音,使用string读入NN

  2. 随后遍历,注意行末没有空格即可;

PotremZ の C++ 解決策

#include<cstdio>
#include<iostream>
#include<map>
using namespace std;
map<int,string>mp;
int main(){
	mp[0]="ling";
	mp[1]="yi";
	mp[2]="er";
	mp[3]="san";
	mp[4]="si";
	mp[5]="wu";
	mp[6]="liu";
	mp[7]="qi";
	mp[8]="ba";
	mp[9]="jiu";
	mp[10]="fu";
	string n; cin>>n;
	for(int i=0;i<n.size();++i){
		if(n[i]=='-') cout<<mp[10];
		else cout<<mp[n[i]-'0'];
		printf("%c",i==n.size()-1 ? 0 : ' ');
	}
	return 0;
}

winterl の Python 解決策

# 打一个字典表,后面直接查就完了
PINYIN_MAP = {
    "0": "ling",
    "1": "yi",
    "2": "er",
    "3": "san",
    "4": "si",
    "5": "wu",
    "6": "liu",
    "7": "qi",
    "8": "ba",
    "9": "jiu",
    "-": "fu",
}

answer = []
for char in input():
    answer.append(PINYIN_MAP[char])

print(" ".join(answer))

L1-008 求整数段和 (10 分)

给定两个整数AABB,输出从AABB的所有整数以及这些数的和。

输入格式

输入在一行中给个整数AABB,其中100AB100−100 \leqslant A \leqslant B \leqslant 100,其间以空格分隔。

输出格式

首先顺序输出从A到B的所有整数,每55个数字占一行,每个数字占55个字符宽度,向右对齐。最后在一行中按Sum = X的格式输出全部数字的和X

输入样例

-3 8

输出样例

   -3   -2   -1    0    1
    2    3    4    5    6
    7    8
Sum = 30

作者:杨起帆
单位:浙大城市学院
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ の C++ 解決策

#include<cstdio>
int main(){
	int a,b; scanf("%d %d",&a,&b);
	int i=a;
	while(i<=b){
		for(int j=1;j<=5;++j){
			printf("%5d",i); if(j==5) puts("");
			++i;
			if(i==b+1){
				if(j!=5) puts("");
				printf("Sum = %d",(a+b)*(b-a+1)/2);
				return 0;
			}
		}
	}
	return 0;
}

winterl の Python 解決策

lower, upper = map(int, input().split())
total = 0
counter = 0 # 记录一行打了多少个
for value in range(lower, upper + 1):
    total += value
    if counter == 5:
        counter = 0
        print()
    # 格式化字符串,保留五位宽度
    print(f"{value:>5}", end="")
    counter += 1
print(f"\nSum = {total}")

L1-009 N个数求和 (20 分)

本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。

输入格式

输入第一行给出一个正整数N(100)( \leqslant 100)。随后一行按格式a1/b1 a2/b2 ...给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。

输出格式

输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为00,则只输出分数部分。

输入样例1

5
2/5 4/15 1/30 -2/60 8/3

输出样例1

3 1/3

输入样例2

2
4/3 2/3

输出样例2

2

输入样例3

3
1/3 -1/6 1/8

输出样例3

7/24

作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ’s Solution

思路来自 ChangeG 的N个数求和(PTA)

1.对当前读入的有理数,直接与之前输入的有理数相加,再化为最简形式;

2.设之前输入的有理数的和的形式为asumbsum\frac{a_{sum}}{b_{sum}},当前读入的有理数为ab\frac{a}{b}

3.显然通分结果为bsumbb_{sum}*b,则通分后,两数分别为asumbbsumb,  absumbbsum\frac{a_{sum}*b}{b_{sum}*b},\;\frac{a*b_{sum}}{b*b_{sum}},则合并结果为asumb+absumbsumb\frac{a_{sum}*b+a*b_{sum}}{b_{sum}*b}

4.对于累加后的 新的asumbsum\frac{a_{sum}}{b_{sum}},设tmp=gcd(asum,bsum)tmp=gcd(a_{sum},b_{sum}),则tmptmpasum,bsuma_{sum},b_{sum}的最大公因子,上下同除tmptmp可以使分数最简化;

5.最后对整数部分进行判断,注意输出格式即可;

原博主这么写过:-3/2的时候他们的结果都是-1 1/-2,但他给出的代码会输出-1 1/2,本人认为答案应该为-1 -1/2,因为一般认为最简形式其实应该为整数部分+分数部分,所以分数部分也应是负数;

PotremZ の C++ 解決策

#include<cstdio>
#include<algorithm>
#define ll long long
ll a,b,suma,sumb=1;
ll gcd(ll x,ll y){ return y==0 ? x : gcd(y,x%y); }
int main(){
	int n; scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%lld/%lld",&a,&b);
		suma=suma*b+a*sumb;
		sumb=sumb*b;
		ll tmp=gcd(suma,sumb);
		suma/=tmp; sumb/=tmp;
	}
	if(suma==0) puts("0");//特判0
	else {
		if(suma/sumb) printf("%lld",suma/sumb);
		if(suma%sumb){
			if(suma/sumb) printf(" ");//格式格式
			if(suma*sumb<0) printf("-");
			printf("%lld/%lld\n",abs(suma%sumb),abs(sumb));
		}
	}
	return 0;
}

winterl の Python 解決策

# 标准库大法,Python最大的优势就是标准库,一定要好好利用
from fractions import Fraction
_ = input()
# 不用标准库 这里就需要先把分子分母分开存
fractions = map(Fraction, input().split())
# 直接计算求和,并且求出分子分母
top, bottom = sum(fractions).as_integer_ratio()
if bottom == 1: # 分子为 1 表示是一个整数
    print(top)
else:
    # 注意,不要用自带的整除,或者divmod,神坑
    div = int(top / bottom)
    mod = top - div * bottom
    if div != 0: # 是一个带分数
        print(div, f"{mod}/{bottom}")
    else:
        print(f"{mod}/{bottom}")

L1-010 比较大小 (10 分)

本题要求将输入的任意33个整数从小到大输出。

输入格式

输入在一行中给出33个整数,其间以空格分隔。

输出格式

在一行中将33个整数从小到大输出,其间以->相连。

输入样例

4 2 8

输出样例

2->4->8

作者:杨起帆
单位:浙大城市学院
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB

PotremZ の C++ 解決策

#include<cstdio>
#include<algorithm>
int main(){
	int x[3]; scanf("%d %d %d",&x[0],&x[1],&x[2]);
	std::sort(x,x+3);
	printf("%d->%d->%d",x[0],x[1],x[2]);
	return 0;
}

winterl の Python 解決策

# 水题,秒了(bushi)
print("->".join(map(str, sorted(map(int, input().split())))))

# lst = map(int, input().split())
# lst = sorted(lst)
# str_lst = map(str, lst)
# print("->".join(str_lst))

团队天梯赛练习题题解 L1-001~L1-010
https://winterl-blog.netlify.app/2025/01/20/团队天梯赛练习题题解 L1-001~L1-010/
作者
PotremZ, winterl
发布于
2025年1月20日
许可协议