第五届传智杯 | 初赛 | python 解法思路复盘

A-莲子的软件工程学

题目描述

具体而言,给定两个整数 a , b a,b a,b,保证 b ≠ 0 b\neq 0 b=0。莲子要实现这样一个函数 fun ⁡ ( a , b ) \operatorname{fun}(a,b) fun(a,b) 来将 b b b 的符号转移到 a a a 上。

具体而言, fun ⁡ ( a , b ) = sgn ⁡ ( b ) × ∣ a ∣ \operatorname{fun}(a,b)=\operatorname{sgn}(b)\times |a| fun(a,b)=sgn(b)×a。其中, sgn ⁡ ( b ) = { 1 b > 0 − 1 b < 0 \operatorname{sgn}(b)=\begin{cases}1&b>0\\-1&b<0\end{cases} sgn(b)={11b>0b<0

换而言之:

  • 如果 b b b 是正数,那么 fun ⁡ ( a , b ) = + ∣ a ∣ = ∣ a ∣ \operatorname{fun}(a,b)=+|a|=|a| fun(a,b)=+a=a
  • 如果 b b b 是负数,那么 fun ⁡ ( a , b ) = − ∣ a ∣ \operatorname{fun}(a,b)=-|a| fun(a,b)=a

如果使用一个三维坐标系描述 fun ⁡ ( a , b ) \operatorname{fun}(a,b) fun(a,b),则应当如下图所示:

你只需输出 fun ⁡ ( a , b ) \operatorname{fun}(a,b) fun(a,b) 的值。

输入格式

  • 共一行两个整数 a , b a,b a,b

输出格式

  • 共一行一个整数 fun ⁡ ( a , b ) \operatorname{fun}(a,b) fun(a,b) 的值。

样例

样例输入

-1 2

样例输出

1

样例输入

0 -4

样例输出

0

样例输入

-12345 -54321

样例输出

-12345

提示

对于全部数据,保证 a , b a,b a,b 32 32 32 位有符号整型范围内,并且 b ≠ 0 b \neq 0 b=0

我的思路

在这里插入图片描述

第一次打开传智杯的题目,又是给图又是描述的,看得出传智杯的题目风格很严谨,篇幅稍长。
A题打卡题,只要稍微熟悉一点语言就没问题,用abs()绝对值函数可以省事很多

源代码

a,b=map(int,input().split(' '))
def sub(b):
    if b>0:
        return 1
    else:return -1
def fun(a,b):
    return abs(a)*sub(b)

print(fun(a,b))

相比看来,python代码似乎的却很简洁

B-莲子的机械动力学

题目描述

题目背景的问题可以转化为如下描述:

给定两个长度分别为 n , m n,m n,m 的整数 a , b a,b a,b,计算它们的和。

但是要注意的是,这里的 a , b a,b a,b 采用了某种特殊的进制表示法。最终的结果也会采用该种表示法。具体而言,从低位往高位数起,第 i i i 位采用的是 i + 1 i+1 i+1 进制。换言之,相较于十进制下每一位的「逢 10 10 10 1 1 1」,该种进制下第 i i i 位是「逢 i + 1 i+1 i+1 1 1 1」。

下图所示,左边是十进制的竖式加法;右边是这种特殊进制的竖式加法。图中的红色加号表示上一位发生了进位。

输入格式

  • 第一行有两个整数 n , m n,m n,m,分别表示 a a a b b b 的位数。
  • 第二行有 n n n 个整数,中间用空格隔开,从高到低位描述 a a a 的每个数码。
  • 第三行有 m m m 个整数,中间用空格隔开,从高到低位描述 b b b 的每个数码。

输出格式

  • 输出有若干个整数,从高到低位输出 a + b a+b a+b 在这种特殊表示法下的结果。

样例

样例输入

5 4
3 3 2 1 1
3 2 2 1

样例输出

4 2 1 1 0

样例输入

10 1
10 9 8 7 6 5 4 3 2 1
0

样例输出

10 9 8 7 6 5 4 3 2 1

提示

对于全部数据,保证 1 ≤ n , m ≤ 2 × 1 0 5 1\le n,m\le 2\times 10^5 1n,m2×105,从低位往高位数起有 a i ∈ [ 0 , i ] a_i\in[0,i] ai[0,i] b i ∈ [ 0 , i ] b_i\in[0,i] bi[0,i]。请使用 Java 或 Python 语言作答的选手注意输入输出时的效率。

我的思路

在这里插入图片描述

  1. 读懂题目:
    看着题目背景一开始被吓到了,那么长、又是进制题。但耐心读下来发现,其实就是解决一个随着位数增长、进制数也一起增长的特别的加法而已

  2. 输入数据预处理:
    输入两个数组不等长,为方便加法,两个数组都在高位补零至等长,长度为两个数组中较长的数组长度+1,加一是因为在最高位做加法时也可能进位

  3. 核心加法部分:
    抱着脑袋想一会儿,会发现进制数随数组位数改变,且这个改变是固定的,进制数=数组位数+2
    再想一会儿,会发现每位做加法时,位的值=两个数的和%进制数(取模),而加法在进位时,设进位的值为temp,那么temp=两个数的和//进制数(整除)

  4. 丢分反思:
    (1)没想到最高位进位时候的情况,导致一些数据集错误
    (2)进位的值的逻辑差了一小点,导致做加法时有瑕疵,就差了这句:

  • 时间复杂度:遍历一遍数组长度,应该是O(n)
 temp = 0 #每次加法后进位值要初始化成0

源代码

n,m=map(int,input().split(' '))

a=list(map(int,input().split(' ')))
b=list(map(int,input().split(' ')))

a=a[::-1]  #倒转数组
b=b[::-1]
sum=[]
ma_le=max(len(a),len(b))
mi_le=min(len(a),len(b))

#2.输入数据预处理:
#输入两个数组不等长,为方便加法,两个数组都在高位补零至等长,
#长度为两个数组中较长的数组长度+1,加一是因为在最高位做加法时也可能进位

for i in range(ma_le-mi_le+1):
    if len(a)<len(b):
        a.append(0)
    else:b.append(0)

if len(a)<len(b):
    a.append(0)
else:b.append(0)


# 核心加法部分
temp=0 #设进位的值为temp
for i in range(ma_le+1): #遍历 较长数组长度加一 次
    ad=a[i]+b[i]+temp #每位两个数字加进位值的总和
    temp = 0 #每次加法后进位值要初始化成0
    if ad>=i+2:  #发生进位
        sum.append(ad%(i+2)) #位的值=两个数的和%进制数
        temp=ad//(i+2)  #进位值=两个数的和//进制数
    elif ad<i+2: #不发生进位
        sum.append(ad)
        
#最高位可能有0冗余,格式化后输出

sum=sum[::-1]
if len(sum)>1:
    if sum[0]==0:
        sum.remove(0)

# 输出格式
for i in sum:
    print(i,end=' ')

E-梅莉的市场经济学

题目描述

市场每一天的贸易差可以视为一个有周期性规律的数列 a a a [ 0 ] , [ 0 , 1 , 0 , − 1 , 0 ] , [ 0 , 1 , 2 , 1 , 0 , − 1 , − 2 , − 1 , 0 ] , [ 0 , 1 , 2 , 3 , 2 , 1 , 0 , − 1 , − 2 , − 3 , − 2 , − 1 , 0 ] … \color{red}[0],\color{blue}[0,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak 0],\color{red}[0,\allowbreak 1,\allowbreak 2,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak -2,\allowbreak -1,\allowbreak 0],\allowbreak \color{blue}[0,\allowbreak 1,\allowbreak 2,\allowbreak 3,\allowbreak 2,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak -2,\allowbreak -3,\allowbreak -2,\allowbreak -1,\allowbreak 0]\dots [0],[0,1,0,1,0],[0,1,2,1,0,1,2,1,0],[0,1,2,3,2,1,0,1,2,3,2,1,0] 具体而言, a a a 可以被分为无穷段,第 i i i 段的内容为 { 0 , 1 , ⋯   , i , i − 1 , ⋯   , 0 , − 1 , ⋯   , − i , − i + 1 , ⋯ 0 } \{0,\allowbreak 1,\allowbreak \cdots,\allowbreak i,\allowbreak i-1,\allowbreak \cdots,0,\allowbreak -1,\allowbreak \cdots,\allowbreak -i,\allowbreak -i+1,\allowbreak \cdots 0\} {0,1,,i,i1,,0,1,,i,i+1,0}。如下图所示,是将 a a a 数列内的前一些点绘制在坐标轴上的情况:

现在梅莉对市场发起了 q q q 次询问,每次她会给定一个 k k k,希望求出 a k a_k ak 是多少。

输入格式

  • 第一行有一个正整数 q q q,表示询问次数。
  • 接下来 q q q 行,每行一个正整数 k k k,描述每次询问。

输出格式

  • 输出共 q q q 行。对于每次询问,输出对应的结果。

样例

样例输入

9
1
10
100
1000
10000
100000
1000000
10000000
100000000

样例输出

0
1
6
-9
-11
-128
406
1629
5154

提示

对于所有数据, 1 ≤ q ≤ 1 0 5 1 \leq q \leq 10^5 1q105 1 ≤ k ≤ 4 × 1 0 18 1 \leq k \leq 4\times 10^{18} 1k4×1018

我的思路

在这里插入图片描述

  1. 理解题目:
    构造出上面那个分段波形图,输入一串X坐标的值,输出X在图中对应的Y值
  2. 求出X所在波形的顶点:
    图形由有规律的波形衔接而成,每个波形的顶点top依次加一,每个波形的横坐标长度为top*4,找到这个规律就能推算出每个以top为编号的波形在x轴上的位置。 既然输入的是X值,那就找到此X所在的波形(找对应的top)
    具体地,就是用高中的等差数列求和公式,可以构造出一个求位置方程 0=2top^2+3*top+1-x,这个方程的对称轴为-3/4,开口向上,定义域为0到正无穷,所以,对这个方程使用求根公式并向上取整就能得出此时X所在波形的top:
top=  ceil((-3 + sqrt(1 + 8 * x)) / 4) #每个波形的顶点值
  1. 找波形内相对位置:
    找到此波形的top了,就能用求位置方程 得出上一个波形的结束位置last_dot = top + 2 * (top - 1) * ((top - 1) + 1),以此就能计算此时X在此波形中的相对位置rel_dot = x - last_dot - 1
  2. 分段函数的反思:
    相对位置也找到了,接下来只需把每个波形的三段分别用top和相对位置表示出来即可,规律很好找,有能力还可以用pyplot 工具画一个图,对比题目里面图的一模一样就不会出现纰漏了在这里插入图片描述
if 0 <= rel_dot < top: #分段函数
    return  rel_dot
elif top <= rel_dot < 3 * top:
    return -rel_dot + 2 * top
elif 3 * top <= rel_dot <= 4 * top:
    return rel_dot - 4 * top

比赛的时候我就是在分段函数上写错了一点,满盘皆输!!

  • 时间复杂度:纯公式 O(1)

源代码

from math import ceil, sqrt
# import numpy as np
# from matplotlib import pyplot as plt
def fun(x):
    top=  ceil((-3 + sqrt(1 + 8 * x)) / 4) #每个波形的顶点值
    last_dot = top + 2 * (top - 1) * ((top - 1) + 1) #上一个波形的结束点
    rel_dot = x - last_dot - 1 #在此波形中的相对位置
    if 0 <= rel_dot < top: #分段函数
        return  rel_dot
    elif top <= rel_dot < 3 * top:
        return -rel_dot + 2 * top
    elif 3 * top <= rel_dot <= 4 * top:
        return rel_dot - 4 * top

q=int(input())
for i in range(q):
    print(fun(int(input())))
# x=np.linspace(0,30, 1000)
# y = np.array([fun(each) for each in x]) #根据x计算各点函数值

# plt.figure()
# plt.plot(x, y)
# plt.ylim(-5,5)   #限制y的范围
# plt.xlim(0,30)        #限制x的范围
# plt.show()

待续…✌️

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汤米尼克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值